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

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

Issue 1559123003: [turbofan] Performance enhancements for escape analysis (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Fix fix Created 4 years, 11 months 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/pipeline.cc » ('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 <limits>
8
7 #include "src/base/flags.h" 9 #include "src/base/flags.h"
8 #include "src/bootstrapper.h" 10 #include "src/bootstrapper.h"
9 #include "src/compilation-dependencies.h" 11 #include "src/compilation-dependencies.h"
10 #include "src/compiler/common-operator.h" 12 #include "src/compiler/common-operator.h"
11 #include "src/compiler/graph-reducer.h" 13 #include "src/compiler/graph-reducer.h"
12 #include "src/compiler/js-operator.h" 14 #include "src/compiler/js-operator.h"
13 #include "src/compiler/node.h" 15 #include "src/compiler/node.h"
14 #include "src/compiler/node-matchers.h" 16 #include "src/compiler/node-matchers.h"
15 #include "src/compiler/node-properties.h" 17 #include "src/compiler/node-properties.h"
18 #include "src/compiler/operator-properties.h"
16 #include "src/compiler/simplified-operator.h" 19 #include "src/compiler/simplified-operator.h"
17 #include "src/objects-inl.h" 20 #include "src/objects-inl.h"
18 #include "src/type-cache.h" 21 #include "src/type-cache.h"
19 22
20 namespace v8 { 23 namespace v8 {
21 namespace internal { 24 namespace internal {
22 namespace compiler { 25 namespace compiler {
23 26
27 const EscapeAnalysis::Alias EscapeAnalysis::kNotReachable =
28 std::numeric_limits<Alias>::max();
29 const EscapeAnalysis::Alias EscapeAnalysis::kUntrackable =
30 std::numeric_limits<Alias>::max() - 1;
31
32
24 class VirtualObject : public ZoneObject { 33 class VirtualObject : public ZoneObject {
25 public: 34 public:
26 enum Status { kUntracked = 0, kTracked = 1 }; 35 enum Status { kUntracked = 0, kTracked = 1 };
27 VirtualObject(NodeId id, Zone* zone) 36 VirtualObject(NodeId id, Zone* zone)
28 : id_(id), 37 : id_(id),
29 status_(kUntracked), 38 status_(kUntracked),
30 fields_(zone), 39 fields_(zone),
31 phi_(zone), 40 phi_(zone),
32 object_state_(nullptr) {} 41 object_state_(nullptr) {}
33 42
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 if (fields_[i] != nullptr) { 100 if (fields_[i] != nullptr) {
92 fields_[i] = nullptr; 101 fields_[i] = nullptr;
93 changed = true; 102 changed = true;
94 } 103 }
95 phi_[i] = false; 104 phi_[i] = false;
96 } 105 }
97 return changed; 106 return changed;
98 } 107 }
99 bool UpdateFrom(const VirtualObject& other); 108 bool UpdateFrom(const VirtualObject& other);
100 void SetObjectState(Node* node) { object_state_ = node; } 109 void SetObjectState(Node* node) { object_state_ = node; }
101 Node* GetObjectState() { return object_state_; } 110 Node* GetObjectState() const { return object_state_; }
102 111
103 NodeId id() { return id_; } 112 NodeId id() const { return id_; }
104 void id(NodeId id) { id_ = id; } 113 void id(NodeId id) { id_ = id; }
105 114
106 private: 115 private:
107 NodeId id_; 116 NodeId id_;
108 Status status_; 117 Status status_;
109 ZoneVector<Node*> fields_; 118 ZoneVector<Node*> fields_;
110 ZoneVector<bool> phi_; 119 ZoneVector<bool> phi_;
111 Node* object_state_; 120 Node* object_state_;
112 }; 121 };
113 122
(...skipping 13 matching lines...) Expand all
127 } 136 }
128 return changed; 137 return changed;
129 } 138 }
130 139
131 140
132 class VirtualState : public ZoneObject { 141 class VirtualState : public ZoneObject {
133 public: 142 public:
134 VirtualState(Zone* zone, size_t size); 143 VirtualState(Zone* zone, size_t size);
135 VirtualState(const VirtualState& states); 144 VirtualState(const VirtualState& states);
136 145
137 VirtualObject* GetVirtualObject(Node* node); 146 VirtualObject* VirtualObjectFromAlias(size_t alias);
138 VirtualObject* GetVirtualObject(size_t id); 147 VirtualObject* GetOrCreateTrackedVirtualObject(EscapeAnalysis::Alias alias,
139 VirtualObject* GetOrCreateTrackedVirtualObject(NodeId id, Zone* zone); 148 NodeId id, Zone* zone);
140 void SetVirtualObject(NodeId id, VirtualObject* state); 149 void SetVirtualObject(EscapeAnalysis::Alias alias, VirtualObject* state);
141 void LastChangedAt(Node* node) { last_changed_ = node; } 150 void LastChangedAt(Node* node) { last_changed_ = node; }
142 Node* GetLastChanged() { return last_changed_; } 151 Node* GetLastChanged() { return last_changed_; }
143 bool UpdateFrom(NodeId id, VirtualObject* state, Zone* zone);
144 bool UpdateFrom(VirtualState* state, Zone* zone); 152 bool UpdateFrom(VirtualState* state, Zone* zone);
145 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, 153 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
146 CommonOperatorBuilder* common, Node* control); 154 CommonOperatorBuilder* common, Node* control);
147 155 size_t size() const { return info_.size(); }
148 size_t size() { return info_.size(); }
149 156
150 private: 157 private:
151 ZoneVector<VirtualObject*> info_; 158 ZoneVector<VirtualObject*> info_;
152 Node* last_changed_; 159 Node* last_changed_;
153 }; 160 };
154 161
155 162
156 class MergeCache : public ZoneObject { 163 class MergeCache : public ZoneObject {
157 public: 164 public:
158 explicit MergeCache(Zone* zone) 165 explicit MergeCache(Zone* zone)
159 : states_(zone), objects_(zone), fields_(zone), min_size_(SIZE_MAX) { 166 : states_(zone), objects_(zone), fields_(zone) {
160 states_.reserve(4); 167 states_.reserve(4);
161 objects_.reserve(4); 168 objects_.reserve(4);
162 fields_.reserve(4); 169 fields_.reserve(4);
163 } 170 }
164 ZoneVector<VirtualState*>& states() { return states_; } 171 ZoneVector<VirtualState*>& states() { return states_; }
165 ZoneVector<VirtualObject*>& objects() { return objects_; } 172 ZoneVector<VirtualObject*>& objects() { return objects_; }
166 ZoneVector<Node*>& fields() { return fields_; } 173 ZoneVector<Node*>& fields() { return fields_; }
167 void Clear() { 174 void Clear() {
168 states_.clear(); 175 states_.clear();
169 objects_.clear(); 176 objects_.clear();
170 fields_.clear(); 177 fields_.clear();
171 min_size_ = SIZE_MAX;
172 } 178 }
173 void push_back(VirtualState* state) { 179 size_t LoadVirtualObjectsFromStatesFor(EscapeAnalysis::Alias alias);
174 states_.push_back(state); 180 void LoadVirtualObjectsForFieldsFrom(
175 min_size_ = std::min(state->size(), min_size_); 181 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases);
176 }
177 size_t min_size() { return min_size_; }
178
179 size_t LoadVirtualObjectsFromStatesFor(NodeId id);
180 void LoadVirtualObjectsForFieldsFrom(VirtualState* state);
181 Node* GetFields(size_t pos); 182 Node* GetFields(size_t pos);
182 183
183 private: 184 private:
184 ZoneVector<VirtualState*> states_; 185 ZoneVector<VirtualState*> states_;
185 ZoneVector<VirtualObject*> objects_; 186 ZoneVector<VirtualObject*> objects_;
186 ZoneVector<Node*> fields_; 187 ZoneVector<Node*> fields_;
187 size_t min_size_;
188 }; 188 };
189 189
190 190
191 size_t MergeCache::LoadVirtualObjectsFromStatesFor(NodeId id) { 191 size_t MergeCache::LoadVirtualObjectsFromStatesFor(
192 EscapeAnalysis::Alias alias) {
192 objects_.clear(); 193 objects_.clear();
193 DCHECK_GT(states_.size(), 0u); 194 DCHECK_GT(states_.size(), 0u);
194 size_t min = SIZE_MAX; 195 size_t min = std::numeric_limits<size_t>::max();
195 for (VirtualState* state : states_) { 196 for (VirtualState* state : states_) {
196 if (VirtualObject* obj = state->GetVirtualObject(id)) { 197 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
197 objects_.push_back(obj); 198 objects_.push_back(obj);
198 min = std::min(obj->field_count(), min); 199 min = std::min(obj->field_count(), min);
199 } 200 }
200 } 201 }
201 return min; 202 return min;
202 } 203 }
203 204
204 205
205 void MergeCache::LoadVirtualObjectsForFieldsFrom(VirtualState* state) { 206 void MergeCache::LoadVirtualObjectsForFieldsFrom(
207 VirtualState* state, const ZoneVector<EscapeAnalysis::Alias>& aliases) {
206 objects_.clear(); 208 objects_.clear();
209 size_t max_alias = state->size();
207 for (Node* field : fields_) { 210 for (Node* field : fields_) {
208 if (VirtualObject* obj = state->GetVirtualObject(field)) { 211 EscapeAnalysis::Alias alias = aliases[field->id()];
212 if (alias >= max_alias) continue;
213 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
209 objects_.push_back(obj); 214 objects_.push_back(obj);
210 } 215 }
211 } 216 }
212 } 217 }
213 218
214 219
215 Node* MergeCache::GetFields(size_t pos) { 220 Node* MergeCache::GetFields(size_t pos) {
216 fields_.clear(); 221 fields_.clear();
217 Node* rep = objects_.front()->GetField(pos); 222 Node* rep = objects_.front()->GetField(pos);
218 for (VirtualObject* obj : objects_) { 223 for (VirtualObject* obj : objects_) {
(...skipping 10 matching lines...) Expand all
229 234
230 235
231 VirtualState::VirtualState(Zone* zone, size_t size) 236 VirtualState::VirtualState(Zone* zone, size_t size)
232 : info_(size, nullptr, zone), last_changed_(nullptr) {} 237 : info_(size, nullptr, zone), last_changed_(nullptr) {}
233 238
234 239
235 VirtualState::VirtualState(const VirtualState& state) 240 VirtualState::VirtualState(const VirtualState& state)
236 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), 241 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()),
237 last_changed_(state.last_changed_) { 242 last_changed_(state.last_changed_) {
238 for (size_t i = 0; i < state.info_.size(); ++i) { 243 for (size_t i = 0; i < state.info_.size(); ++i) {
239 if (state.info_[i] && state.info_[i]->id() == i) { 244 if (state.info_[i]) {
240 info_[i] = new (state.info_.get_allocator().zone()) 245 info_[i] =
241 VirtualObject(*state.info_[i]); 246 new (info_.get_allocator().zone()) VirtualObject(*state.info_[i]);
242 }
243 }
244 for (size_t i = 0; i < state.info_.size(); ++i) {
245 if (state.info_[i] && state.info_[i]->id() != i) {
246 info_[i] = info_[state.info_[i]->id()];
247 } 247 }
248 } 248 }
249 } 249 }
250 250
251 251
252 VirtualObject* VirtualState::GetVirtualObject(size_t id) { 252 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) {
253 if (id >= info_.size()) return nullptr; 253 return info_[alias];
254 return info_[id];
255 } 254 }
256 255
257 256
258 VirtualObject* VirtualState::GetVirtualObject(Node* node) { 257 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(
259 return GetVirtualObject(node->id()); 258 EscapeAnalysis::Alias alias, NodeId id, Zone* zone) {
260 } 259 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) {
261
262
263 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject(NodeId id,
264 Zone* zone) {
265 if (VirtualObject* obj = GetVirtualObject(id)) {
266 return obj; 260 return obj;
267 } 261 }
268 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0); 262 VirtualObject* obj = new (zone) VirtualObject(id, zone, 0);
269 SetVirtualObject(id, obj); 263 SetVirtualObject(alias, obj);
270 return obj; 264 return obj;
271 } 265 }
272 266
273 267
274 void VirtualState::SetVirtualObject(NodeId id, VirtualObject* obj) { 268 void VirtualState::SetVirtualObject(EscapeAnalysis::Alias alias,
275 info_[id] = obj; 269 VirtualObject* obj) {
276 } 270 info_[alias] = obj;
277
278
279 bool VirtualState::UpdateFrom(NodeId id, VirtualObject* fromObj, Zone* zone) {
280 VirtualObject* obj = GetVirtualObject(id);
281 if (!obj) {
282 obj = new (zone) VirtualObject(*fromObj);
283 SetVirtualObject(id, obj);
284 if (FLAG_trace_turbo_escape) {
285 PrintF(" Taking field for #%d from %p\n", id,
286 static_cast<void*>(fromObj));
287 }
288 return true;
289 }
290
291 if (obj->UpdateFrom(*fromObj)) {
292 if (FLAG_trace_turbo_escape) {
293 PrintF(" Updating field for #%d from %p\n", id,
294 static_cast<void*>(fromObj));
295 }
296 return true;
297 }
298
299 return false;
300 } 271 }
301 272
302 273
303 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { 274 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
304 bool changed = false; 275 bool changed = false;
305 for (NodeId id = 0; id < size(); ++id) { 276 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) {
306 VirtualObject* ls = GetVirtualObject(id); 277 VirtualObject* ls = VirtualObjectFromAlias(alias);
307 VirtualObject* rs = from->GetVirtualObject(id); 278 VirtualObject* rs = from->VirtualObjectFromAlias(alias);
308 279
309 if (rs == nullptr) { 280 if (rs == nullptr) {
310 continue; 281 continue;
311 } 282 }
312 283
313 if (ls == nullptr) { 284 if (ls == nullptr) {
314 ls = new (zone) VirtualObject(*rs); 285 ls = new (zone) VirtualObject(*rs);
315 SetVirtualObject(id, ls); 286 SetVirtualObject(alias, ls);
316 changed = true; 287 changed = true;
317 continue; 288 continue;
318 } 289 }
319 290
320 if (FLAG_trace_turbo_escape) { 291 if (FLAG_trace_turbo_escape) {
321 PrintF(" Updating fields of #%d\n", id); 292 PrintF(" Updating fields of @%d\n", alias);
322 } 293 }
323 294
324 changed = ls->UpdateFrom(*rs) || changed; 295 changed = ls->UpdateFrom(*rs) || changed;
325 } 296 }
326 return false; 297 return false;
327 } 298 }
328 299
329 300
330 namespace { 301 namespace {
331 302
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 } 342 }
372 } 343 }
373 return rep; 344 return rep;
374 } 345 }
375 346
376 347
377 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, 348 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
378 CommonOperatorBuilder* common, Node* control) { 349 CommonOperatorBuilder* common, Node* control) {
379 DCHECK_GT(cache->states().size(), 0u); 350 DCHECK_GT(cache->states().size(), 0u);
380 bool changed = false; 351 bool changed = false;
381 for (NodeId id = 0; id < cache->min_size(); ++id) { 352 for (EscapeAnalysis::Alias alias = 0; alias < size(); ++alias) {
382 size_t fields = cache->LoadVirtualObjectsFromStatesFor(id); 353 size_t fields = cache->LoadVirtualObjectsFromStatesFor(alias);
383 if (cache->objects().size() == cache->states().size()) { 354 if (cache->objects().size() == cache->states().size()) {
384 // Don't process linked objects.
385 if (cache->objects()[0]->id() != id) continue;
386 if (FLAG_trace_turbo_escape) { 355 if (FLAG_trace_turbo_escape) {
387 PrintF(" Merging virtual objects of #%d\n", id); 356 PrintF(" Merging virtual objects of @%d\n", alias);
388 } 357 }
389 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(id, zone); 358 VirtualObject* mergeObject = GetOrCreateTrackedVirtualObject(
359 alias, cache->objects().front()->id(), zone);
390 changed = mergeObject->ResizeFields(fields) || changed; 360 changed = mergeObject->ResizeFields(fields) || changed;
391 for (size_t i = 0; i < fields; ++i) { 361 for (size_t i = 0; i < fields; ++i) {
392 if (Node* field = cache->GetFields(i)) { 362 if (Node* field = cache->GetFields(i)) {
393 changed = mergeObject->SetField(i, field) || changed; 363 changed = mergeObject->SetField(i, field) || changed;
394 if (FLAG_trace_turbo_escape) { 364 if (FLAG_trace_turbo_escape) {
395 PrintF(" Field %zu agree on rep #%d\n", i, field->id()); 365 PrintF(" Field %zu agree on rep #%d\n", i, field->id());
396 } 366 }
397 } else { 367 } else {
398 int value_input_count = static_cast<int>(cache->fields().size()); 368 int value_input_count = static_cast<int>(cache->fields().size());
399 if (cache->fields().size() == cache->objects().size()) { 369 if (cache->fields().size() == cache->objects().size()) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 rep, common->Phi(MachineRepresentation::kTagged, 408 rep, common->Phi(MachineRepresentation::kTagged,
439 value_input_count)); 409 value_input_count));
440 } 410 }
441 } 411 }
442 } else { 412 } else {
443 changed = mergeObject->SetField(i, nullptr) || changed; 413 changed = mergeObject->SetField(i, nullptr) || changed;
444 } 414 }
445 } 415 }
446 } 416 }
447 } else { 417 } else {
448 SetVirtualObject(id, nullptr); 418 SetVirtualObject(alias, nullptr);
449 }
450 }
451 // Update linked objects.
452 for (NodeId id = 0; id < cache->min_size(); ++id) {
453 if (VirtualObject* obj = cache->states().front()->GetVirtualObject(id)) {
454 if (obj->id() != id) {
455 SetVirtualObject(id, GetVirtualObject(obj->id()));
456 }
457 } 419 }
458 } 420 }
459 return changed; 421 return changed;
460 } 422 }
461 423
462 424
463 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, 425 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis,
464 Graph* graph, Zone* zone) 426 Graph* graph, Zone* zone)
465 : object_analysis_(object_analysis), 427 : object_analysis_(object_analysis),
466 graph_(graph), 428 graph_(graph),
467 zone_(zone), 429 zone_(zone),
468 info_(graph->NodeCount(), kUnknown, zone), 430 status_(graph->NodeCount(), kUnknown, zone),
469 queue_(zone) {} 431 queue_(zone) {}
470 432
471 433
472 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} 434 EscapeStatusAnalysis::~EscapeStatusAnalysis() {}
473 435
474 436
475 bool EscapeStatusAnalysis::HasEntry(Node* node) { 437 bool EscapeStatusAnalysis::HasEntry(Node* node) {
476 return info_[node->id()] != kUnknown; 438 return status_[node->id()] & (kTracked | kEscaped);
477 } 439 }
478 440
479 441
480 bool EscapeStatusAnalysis::IsVirtual(Node* node) { 442 bool EscapeStatusAnalysis::IsVirtual(Node* node) {
481 return info_[node->id()] == kVirtual; 443 return (status_[node->id()] & kTracked) && !(status_[node->id()] & kEscaped);
482 } 444 }
483 445
484 446
485 bool EscapeStatusAnalysis::IsEscaped(Node* node) { 447 bool EscapeStatusAnalysis::IsEscaped(Node* node) {
486 return info_[node->id()] == kEscaped; 448 return status_[node->id()] & kEscaped;
487 } 449 }
488 450
489 451
490 bool EscapeStatusAnalysis::IsAllocation(Node* node) { 452 bool EscapeStatusAnalysis::IsAllocation(Node* node) {
491 return node->opcode() == IrOpcode::kAllocate || 453 return node->opcode() == IrOpcode::kAllocate ||
492 node->opcode() == IrOpcode::kFinishRegion; 454 node->opcode() == IrOpcode::kFinishRegion;
493 } 455 }
494 456
495 457
496 bool EscapeStatusAnalysis::SetEscaped(Node* node) { 458 bool EscapeStatusAnalysis::SetEscaped(Node* node) {
497 bool changed = info_[node->id()] != kEscaped; 459 bool changed = !(status_[node->id()] & kEscaped);
498 info_[node->id()] = kEscaped; 460 status_[node->id()] |= kEscaped | kTracked;
499 return changed; 461 return changed;
500 } 462 }
501 463
502 464
503 void EscapeStatusAnalysis::Resize() { 465 void EscapeStatusAnalysis::Resize() {
504 info_.resize(graph()->NodeCount(), kUnknown); 466 status_.resize(graph()->NodeCount(), kUnknown);
505 } 467 }
506 468
507 469
508 size_t EscapeStatusAnalysis::size() { return info_.size(); } 470 size_t EscapeStatusAnalysis::size() { return status_.size(); }
509 471
510 472
511 void EscapeStatusAnalysis::Run() { 473 void EscapeStatusAnalysis::Run() {
512 Resize(); 474 Resize();
513 ZoneVector<bool> visited(zone());
514 visited.resize(graph()->NodeCount());
515 queue_.push_back(graph()->end()); 475 queue_.push_back(graph()->end());
476 status_[graph()->end()->id()] |= kOnStack;
516 while (!queue_.empty()) { 477 while (!queue_.empty()) {
517 Node* node = queue_.front(); 478 Node* node = queue_.front();
518 queue_.pop_front(); 479 queue_.pop_front();
480 status_[node->id()] &= ~kOnStack;
519 Process(node); 481 Process(node);
520 if (!visited[node->id()]) { 482 status_[node->id()] |= kVisited;
521 RevisitInputs(node); 483 for (Edge edge : node->input_edges()) {
484 Node* input = edge.to();
485 if (!(status_[input->id()] & (kVisited | kOnStack))) {
486 queue_.push_back(input);
487 status_[input->id()] |= kOnStack;
488 }
522 } 489 }
523 visited[node->id()] = true;
524 }
525 if (FLAG_trace_turbo_escape) {
526 DebugPrint();
527 } 490 }
528 } 491 }
529 492
530 493
531 void EscapeStatusAnalysis::RevisitInputs(Node* node) { 494 void EscapeStatusAnalysis::RevisitInputs(Node* node) {
532 for (Edge edge : node->input_edges()) { 495 for (Edge edge : node->input_edges()) {
533 Node* input = edge.to(); 496 Node* input = edge.to();
534 queue_.push_back(input); 497 if (!(status_[input->id()] & kOnStack)) {
498 queue_.push_back(input);
499 status_[input->id()] |= kOnStack;
500 }
535 } 501 }
536 } 502 }
537 503
538 504
539 void EscapeStatusAnalysis::RevisitUses(Node* node) { 505 void EscapeStatusAnalysis::RevisitUses(Node* node) {
540 for (Edge edge : node->use_edges()) { 506 for (Edge edge : node->use_edges()) {
541 Node* use = edge.from(); 507 Node* use = edge.from();
542 queue_.push_back(use); 508 if (!(status_[use->id()] & kOnStack)) {
509 queue_.push_back(use);
510 status_[use->id()] |= kOnStack;
511 }
543 } 512 }
544 } 513 }
545 514
546 515
547 void EscapeStatusAnalysis::Process(Node* node) { 516 void EscapeStatusAnalysis::Process(Node* node) {
548 switch (node->opcode()) { 517 switch (node->opcode()) {
549 case IrOpcode::kAllocate: 518 case IrOpcode::kAllocate:
550 ProcessAllocate(node); 519 ProcessAllocate(node);
551 break; 520 break;
552 case IrOpcode::kFinishRegion: 521 case IrOpcode::kFinishRegion:
(...skipping 10 matching lines...) Expand all
563 if (Node* rep = object_analysis_->GetReplacement(node)) { 532 if (Node* rep = object_analysis_->GetReplacement(node)) {
564 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) { 533 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) {
565 RevisitInputs(rep); 534 RevisitInputs(rep);
566 RevisitUses(rep); 535 RevisitUses(rep);
567 } 536 }
568 } 537 }
569 break; 538 break;
570 } 539 }
571 case IrOpcode::kPhi: 540 case IrOpcode::kPhi:
572 if (!HasEntry(node)) { 541 if (!HasEntry(node)) {
573 info_[node->id()] = kVirtual; 542 status_[node->id()] |= kTracked;
574 if (!IsAllocationPhi(node)) { 543 if (!IsAllocationPhi(node)) {
575 SetEscaped(node); 544 SetEscaped(node);
576 RevisitUses(node); 545 RevisitUses(node);
577 } 546 }
578 } 547 }
579 CheckUsesForEscape(node); 548 CheckUsesForEscape(node);
580 default: 549 default:
581 break; 550 break;
582 } 551 }
583 } 552 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n", 589 PrintF("Setting #%d (%s) to escaped because of store to field of #%d\n",
621 val->id(), val->op()->mnemonic(), to->id()); 590 val->id(), val->op()->mnemonic(), to->id());
622 } 591 }
623 } 592 }
624 } 593 }
625 594
626 595
627 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { 596 void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
628 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); 597 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
629 if (!HasEntry(node)) { 598 if (!HasEntry(node)) {
630 info_[node->id()] = kVirtual; 599 status_[node->id()] |= kTracked;
631 if (FLAG_trace_turbo_escape) { 600 if (FLAG_trace_turbo_escape) {
632 PrintF("Created status entry for node #%d (%s)\n", node->id(), 601 PrintF("Created status entry for node #%d (%s)\n", node->id(),
633 node->op()->mnemonic()); 602 node->op()->mnemonic());
634 } 603 }
635 NumberMatcher size(node->InputAt(0)); 604 NumberMatcher size(node->InputAt(0));
636 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && 605 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant &&
637 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && 606 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant &&
638 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && 607 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant &&
639 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); 608 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant);
640 if (!size.HasValue() && SetEscaped(node)) { 609 if (!size.HasValue() && SetEscaped(node)) {
641 RevisitUses(node); 610 RevisitUses(node);
642 if (FLAG_trace_turbo_escape) { 611 if (FLAG_trace_turbo_escape) {
643 PrintF("Setting #%d to escaped because of non-const alloc\n", 612 PrintF("Setting #%d to escaped because of non-const alloc\n",
644 node->id()); 613 node->id());
645 } 614 }
646 // This node is known to escape, uses do not have to be checked. 615 // This node is known to escape, uses do not have to be checked.
647 return; 616 return;
648 } 617 }
649 } 618 }
650 if (CheckUsesForEscape(node, true)) { 619 if (CheckUsesForEscape(node, true)) {
651 RevisitUses(node); 620 RevisitUses(node);
652 } 621 }
653 } 622 }
654 623
655 624
656 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, 625 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
657 bool phi_escaping) { 626 bool phi_escaping) {
658 for (Edge edge : uses->use_edges()) { 627 for (Edge edge : uses->use_edges()) {
659 Node* use = edge.from(); 628 Node* use = edge.from();
660 if (!NodeProperties::IsValueEdge(edge) && 629 if (edge.index() >= use->op()->ValueInputCount() +
661 !NodeProperties::IsContextEdge(edge)) 630 OperatorProperties::GetContextInputCount(use->op()))
662 continue; 631 continue;
663 switch (use->opcode()) { 632 switch (use->opcode()) {
633 case IrOpcode::kPhi:
634 if (phi_escaping && SetEscaped(rep)) {
635 if (FLAG_trace_turbo_escape) {
636 PrintF(
637 "Setting #%d (%s) to escaped because of use by phi node "
638 "#%d (%s)\n",
639 rep->id(), rep->op()->mnemonic(), use->id(),
640 use->op()->mnemonic());
641 }
642 return true;
643 }
644 // Fallthrough.
664 case IrOpcode::kStoreField: 645 case IrOpcode::kStoreField:
665 case IrOpcode::kLoadField: 646 case IrOpcode::kLoadField:
666 case IrOpcode::kStoreElement: 647 case IrOpcode::kStoreElement:
667 case IrOpcode::kLoadElement: 648 case IrOpcode::kLoadElement:
668 case IrOpcode::kFrameState: 649 case IrOpcode::kFrameState:
669 case IrOpcode::kStateValues: 650 case IrOpcode::kStateValues:
670 case IrOpcode::kReferenceEqual: 651 case IrOpcode::kReferenceEqual:
671 case IrOpcode::kFinishRegion: 652 case IrOpcode::kFinishRegion:
672 case IrOpcode::kPhi: 653 if (IsEscaped(use) && SetEscaped(rep)) {
673 if (HasEntry(use) && IsEscaped(use) && SetEscaped(rep)) {
674 if (FLAG_trace_turbo_escape) { 654 if (FLAG_trace_turbo_escape) {
675 PrintF( 655 PrintF(
676 "Setting #%d (%s) to escaped because of use by escaping node " 656 "Setting #%d (%s) to escaped because of use by escaping node "
677 "#%d (%s)\n", 657 "#%d (%s)\n",
678 rep->id(), rep->op()->mnemonic(), use->id(), 658 rep->id(), rep->op()->mnemonic(), use->id(),
679 use->op()->mnemonic()); 659 use->op()->mnemonic());
680 }
681 return true;
682 }
683 if (phi_escaping && use->opcode() == IrOpcode::kPhi &&
684 SetEscaped(rep)) {
685 if (FLAG_trace_turbo_escape) {
686 PrintF(
687 "Setting #%d (%s) to escaped because of use by phi node "
688 "#%d (%s)\n",
689 rep->id(), rep->op()->mnemonic(), use->id(),
690 use->op()->mnemonic());
691 } 660 }
692 return true; 661 return true;
693 } 662 }
694 break; 663 break;
695 case IrOpcode::kObjectIsSmi: 664 case IrOpcode::kObjectIsSmi:
696 if (!IsAllocation(rep) && SetEscaped(rep)) { 665 if (!IsAllocation(rep) && SetEscaped(rep)) {
697 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n", 666 PrintF("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
698 rep->id(), rep->op()->mnemonic(), use->id(), 667 rep->id(), rep->op()->mnemonic(), use->id(),
699 use->op()->mnemonic()); 668 use->op()->mnemonic());
700 return true; 669 return true;
(...skipping 16 matching lines...) Expand all
717 } 686 }
718 } 687 }
719 } 688 }
720 return false; 689 return false;
721 } 690 }
722 691
723 692
724 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { 693 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
725 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); 694 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
726 if (!HasEntry(node)) { 695 if (!HasEntry(node)) {
727 info_[node->id()] = kVirtual; 696 status_[node->id()] |= kTracked;
728 RevisitUses(node); 697 RevisitUses(node);
729 } 698 }
730 if (CheckUsesForEscape(node, true)) { 699 if (CheckUsesForEscape(node, true)) {
731 RevisitInputs(node); 700 RevisitInputs(node);
732 } 701 }
733 } 702 }
734 703
735 704
736 void EscapeStatusAnalysis::DebugPrint() { 705 void EscapeStatusAnalysis::DebugPrint() {
737 for (NodeId id = 0; id < info_.size(); id++) { 706 for (NodeId id = 0; id < status_.size(); id++) {
738 if (info_[id] != kUnknown) { 707 if (status_[id] & kTracked) {
739 PrintF("Node #%d is %s\n", id, 708 PrintF("Node #%d is %s\n", id,
740 info_[id] == kEscaped ? "escaping" : "virtual"); 709 (status_[id] & kEscaped) ? "escaping" : "virtual");
741 } 710 }
742 } 711 }
743 } 712 }
744 713
745 714
746 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, 715 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
747 Zone* zone) 716 Zone* zone)
748 : graph_(graph), 717 : graph_(graph),
749 common_(common), 718 common_(common),
750 zone_(zone), 719 zone_(zone),
751 virtual_states_(zone), 720 virtual_states_(zone),
752 replacements_(zone), 721 replacements_(zone),
753 escape_status_(this, graph, zone), 722 escape_status_(this, graph, zone),
754 cache_(new (zone) MergeCache(zone)) {} 723 cache_(new (zone) MergeCache(zone)),
724 aliases_(zone),
725 next_free_alias_(0) {}
755 726
756 727
757 EscapeAnalysis::~EscapeAnalysis() {} 728 EscapeAnalysis::~EscapeAnalysis() {}
758 729
759 730
760 void EscapeAnalysis::Run() { 731 void EscapeAnalysis::Run() {
761 replacements_.resize(graph()->NodeCount()); 732 replacements_.resize(graph()->NodeCount());
733 AssignAliases();
762 RunObjectAnalysis(); 734 RunObjectAnalysis();
763 escape_status_.Run(); 735 escape_status_.Run();
764 } 736 }
765 737
766 738
739 void EscapeAnalysis::AssignAliases() {
740 ZoneVector<Node*> stack(zone());
741 stack.push_back(graph()->end());
742 CHECK_LT(graph()->NodeCount(), kUntrackable);
743 aliases_.resize(graph()->NodeCount(), kNotReachable);
744 aliases_[graph()->end()->id()] = kUntrackable;
745 while (!stack.empty()) {
746 Node* node = stack.back();
747 stack.pop_back();
748 switch (node->opcode()) {
749 case IrOpcode::kAllocate:
750 if (aliases_[node->id()] >= kUntrackable) {
751 aliases_[node->id()] = NextAlias();
752 }
753 break;
754 case IrOpcode::kFinishRegion: {
755 Node* allocate = NodeProperties::GetValueInput(node, 0);
756 if (allocate->opcode() == IrOpcode::kAllocate) {
757 if (aliases_[allocate->id()] >= kUntrackable) {
758 if (aliases_[allocate->id()] == kNotReachable) {
759 stack.push_back(allocate);
760 }
761 aliases_[allocate->id()] = NextAlias();
762 }
763 aliases_[node->id()] = aliases_[allocate->id()];
764 } else {
765 aliases_[node->id()] = NextAlias();
766 }
767 break;
768 }
769 default:
770 DCHECK_EQ(aliases_[node->id()], kUntrackable);
771 break;
772 }
773 for (Edge edge : node->input_edges()) {
774 Node* input = edge.to();
775 if (aliases_[input->id()] == kNotReachable) {
776 stack.push_back(input);
777 aliases_[input->id()] = kUntrackable;
778 }
779 }
780 }
781
782 if (FLAG_trace_turbo_escape) {
783 PrintF("Discovered trackable nodes");
784 for (EscapeAnalysis::Alias id = 0; id < graph()->NodeCount(); ++id) {
785 if (aliases_[id] < kUntrackable) {
786 if (FLAG_trace_turbo_escape) {
787 PrintF(" #%u", id);
788 }
789 }
790 }
791 PrintF("\n");
792 }
793 }
794
795
767 void EscapeAnalysis::RunObjectAnalysis() { 796 void EscapeAnalysis::RunObjectAnalysis() {
768 virtual_states_.resize(graph()->NodeCount()); 797 virtual_states_.resize(graph()->NodeCount());
769 ZoneVector<Node*> stack(zone()); 798 ZoneVector<Node*> stack(zone());
770 stack.push_back(graph()->start()); 799 stack.push_back(graph()->start());
771 while (!stack.empty()) { 800 while (!stack.empty()) {
772 Node* node = stack.back(); 801 Node* node = stack.back();
773 stack.pop_back(); 802 stack.pop_back();
774 if (Process(node)) { 803 if (aliases_[node->id()] != kNotReachable && Process(node)) {
775 for (Edge edge : node->use_edges()) { 804 for (Edge edge : node->use_edges()) {
776 if (NodeProperties::IsEffectEdge(edge)) { 805 if (NodeProperties::IsEffectEdge(edge)) {
777 Node* use = edge.from(); 806 Node* use = edge.from();
778 if ((use->opcode() != IrOpcode::kLoadField && 807 if ((use->opcode() != IrOpcode::kLoadField &&
779 use->opcode() != IrOpcode::kLoadElement) || 808 use->opcode() != IrOpcode::kLoadElement) ||
780 !IsDanglingEffectNode(use)) { 809 !IsDanglingEffectNode(use)) {
781 stack.push_back(use); 810 stack.push_back(use);
782 } 811 }
783 } 812 }
784 } 813 }
785 // First process loads: dangling loads are a problem otherwise. 814 // First process loads: dangling loads are a problem otherwise.
786 for (Edge edge : node->use_edges()) { 815 for (Edge edge : node->use_edges()) {
787 if (NodeProperties::IsEffectEdge(edge)) { 816 if (NodeProperties::IsEffectEdge(edge)) {
788 Node* use = edge.from(); 817 Node* use = edge.from();
789 if ((use->opcode() == IrOpcode::kLoadField || 818 if ((use->opcode() == IrOpcode::kLoadField ||
790 use->opcode() == IrOpcode::kLoadElement) && 819 use->opcode() == IrOpcode::kLoadElement) &&
791
792
793 IsDanglingEffectNode(use)) { 820 IsDanglingEffectNode(use)) {
794 stack.push_back(use); 821 stack.push_back(use);
795 } 822 }
796 } 823 }
797 } 824 }
798 } 825 }
799 } 826 }
800 if (FLAG_trace_turbo_escape) { 827 if (FLAG_trace_turbo_escape) {
801 DebugPrint(); 828 DebugPrint();
802 } 829 }
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
912 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { 939 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) {
913 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), 940 PrintF("Dangeling effect node: #%d (%s)\n", node->id(),
914 node->op()->mnemonic()); 941 node->op()->mnemonic());
915 UNREACHABLE(); 942 UNREACHABLE();
916 } 943 }
917 Node* effect = NodeProperties::GetEffectInput(node); 944 Node* effect = NodeProperties::GetEffectInput(node);
918 // Break the cycle for effect phis. 945 // Break the cycle for effect phis.
919 if (effect->opcode() == IrOpcode::kEffectPhi) { 946 if (effect->opcode() == IrOpcode::kEffectPhi) {
920 if (virtual_states_[effect->id()] == nullptr) { 947 if (virtual_states_[effect->id()] == nullptr) {
921 virtual_states_[effect->id()] = 948 virtual_states_[effect->id()] =
922 new (zone()) VirtualState(zone(), graph()->NodeCount()); 949 new (zone()) VirtualState(zone(), AliasCount());
923 } 950 }
924 } 951 }
925 DCHECK_NOT_NULL(virtual_states_[effect->id()]); 952 DCHECK_NOT_NULL(virtual_states_[effect->id()]);
926 if (IsEffectBranchPoint(effect)) { 953 if (IsEffectBranchPoint(effect)) {
927 if (FLAG_trace_turbo_escape) { 954 if (FLAG_trace_turbo_escape) {
928 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", 955 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n",
929 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), 956 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
930 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); 957 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
931 } 958 }
932 if (!virtual_states_[node->id()]) { 959 if (!virtual_states_[node->id()]) {
933 virtual_states_[node->id()] = 960 virtual_states_[node->id()] =
934 new (zone()) VirtualState(*virtual_states_[effect->id()]); 961 new (zone()) VirtualState(*virtual_states_[effect->id()]);
935 } else { 962 } else {
936 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], 963 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()],
937 zone()); 964 zone());
938 } 965 }
939 } else { 966 } else {
940 virtual_states_[node->id()] = virtual_states_[effect->id()]; 967 virtual_states_[node->id()] = virtual_states_[effect->id()];
941 if (FLAG_trace_turbo_escape) { 968 if (FLAG_trace_turbo_escape) {
942 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", 969 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n",
943 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), 970 static_cast<void*>(virtual_states_[effect->id()]), effect->id(),
944 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); 971 effect->op()->mnemonic(), node->id(), node->op()->mnemonic());
945 } 972 }
946 } 973 }
947 } 974 }
948 975
949 976
950 void EscapeAnalysis::ProcessStart(Node* node) { 977 void EscapeAnalysis::ProcessStart(Node* node) {
951 DCHECK_EQ(node->opcode(), IrOpcode::kStart); 978 DCHECK_EQ(node->opcode(), IrOpcode::kStart);
952 virtual_states_[node->id()] = 979 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount());
953 new (zone()) VirtualState(zone(), graph()->NodeCount());
954 } 980 }
955 981
956 982
957 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { 983 bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
958 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); 984 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
959 bool changed = false; 985 bool changed = false;
960 986
961 VirtualState* mergeState = virtual_states_[node->id()]; 987 VirtualState* mergeState = virtual_states_[node->id()];
962 if (!mergeState) { 988 if (!mergeState) {
963 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); 989 mergeState = new (zone()) VirtualState(zone(), AliasCount());
964 virtual_states_[node->id()] = mergeState; 990 virtual_states_[node->id()] = mergeState;
965 changed = true; 991 changed = true;
966 if (FLAG_trace_turbo_escape) { 992 if (FLAG_trace_turbo_escape) {
967 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), 993 PrintF("Effect Phi #%d got new states map %p.\n", node->id(),
968 static_cast<void*>(mergeState)); 994 static_cast<void*>(mergeState));
969 } 995 }
970 } else if (mergeState->GetLastChanged() != node) { 996 } else if (mergeState->GetLastChanged() != node) {
971 changed = true; 997 changed = true;
972 } 998 }
973 999
974 cache_->Clear(); 1000 cache_->Clear();
975 1001
976 if (FLAG_trace_turbo_escape) { 1002 if (FLAG_trace_turbo_escape) {
977 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), 1003 PrintF("At Effect Phi #%d, merging states into %p:", node->id(),
978 static_cast<void*>(mergeState)); 1004 static_cast<void*>(mergeState));
979 } 1005 }
980 1006
981 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { 1007 for (int i = 0; i < node->op()->EffectInputCount(); ++i) {
982 Node* input = NodeProperties::GetEffectInput(node, i); 1008 Node* input = NodeProperties::GetEffectInput(node, i);
983 VirtualState* state = virtual_states_[input->id()]; 1009 VirtualState* state = virtual_states_[input->id()];
984 if (state) { 1010 if (state) {
985 cache_->push_back(state); 1011 cache_->states().push_back(state);
986 } 1012 }
987 if (FLAG_trace_turbo_escape) { 1013 if (FLAG_trace_turbo_escape) {
988 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), 1014 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(),
989 input->op()->mnemonic()); 1015 input->op()->mnemonic());
990 } 1016 }
991 } 1017 }
992 if (FLAG_trace_turbo_escape) { 1018 if (FLAG_trace_turbo_escape) {
993 PrintF("\n"); 1019 PrintF("\n");
994 } 1020 }
995 1021
(...skipping 15 matching lines...) Expand all
1011 } 1037 }
1012 return changed; 1038 return changed;
1013 } 1039 }
1014 1040
1015 1041
1016 void EscapeAnalysis::ProcessAllocation(Node* node) { 1042 void EscapeAnalysis::ProcessAllocation(Node* node) {
1017 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); 1043 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
1018 ForwardVirtualState(node); 1044 ForwardVirtualState(node);
1019 1045
1020 // Check if we have already processed this node. 1046 // Check if we have already processed this node.
1021 if (virtual_states_[node->id()]->GetVirtualObject(node)) return; 1047 if (virtual_states_[node->id()]->VirtualObjectFromAlias(
1048 aliases_[node->id()])) {
1049 return;
1050 }
1022 1051
1023 NumberMatcher size(node->InputAt(0)); 1052 NumberMatcher size(node->InputAt(0));
1024 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && 1053 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant &&
1025 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && 1054 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant &&
1026 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && 1055 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant &&
1027 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); 1056 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant);
1028 if (size.HasValue()) { 1057 if (size.HasValue()) {
1029 virtual_states_[node->id()]->SetVirtualObject( 1058 virtual_states_[node->id()]->SetVirtualObject(
1030 node->id(), new (zone()) VirtualObject(node->id(), zone(), 1059 aliases_[node->id()],
1031 size.Value() / kPointerSize)); 1060 new (zone())
1061 VirtualObject(node->id(), zone(), size.Value() / kPointerSize));
1032 } else { 1062 } else {
1033 virtual_states_[node->id()]->SetVirtualObject( 1063 virtual_states_[node->id()]->SetVirtualObject(
1034 node->id(), new (zone()) VirtualObject(node->id(), zone())); 1064 aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone()));
1035 } 1065 }
1036 virtual_states_[node->id()]->LastChangedAt(node); 1066 virtual_states_[node->id()]->LastChangedAt(node);
1037 } 1067 }
1038 1068
1039 1069
1040 void EscapeAnalysis::ProcessFinishRegion(Node* node) { 1070 void EscapeAnalysis::ProcessFinishRegion(Node* node) {
1041 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); 1071 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
1042 ForwardVirtualState(node); 1072 ForwardVirtualState(node);
1043 Node* allocation = NodeProperties::GetValueInput(node, 0); 1073 Node* allocation = NodeProperties::GetValueInput(node, 0);
1044 if (allocation->opcode() == IrOpcode::kAllocate) { 1074 if (allocation->opcode() == IrOpcode::kAllocate) {
1045 VirtualState* states = virtual_states_[node->id()]; 1075 VirtualState* state = virtual_states_[node->id()];
1046 DCHECK_NOT_NULL(states->GetVirtualObject(allocation)); 1076 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) {
1047 if (!states->GetVirtualObject(node->id())) { 1077 VirtualObject* vobj_alloc =
1048 states->SetVirtualObject(node->id(), 1078 state->VirtualObjectFromAlias(aliases_[allocation->id()]);
1049 states->GetVirtualObject(allocation)); 1079 DCHECK_NOT_NULL(vobj_alloc);
1080 state->SetVirtualObject(aliases_[node->id()], vobj_alloc);
1050 if (FLAG_trace_turbo_escape) { 1081 if (FLAG_trace_turbo_escape) {
1051 PrintF("Linked finish region node #%d to node #%d\n", node->id(), 1082 PrintF("Linked finish region node #%d to node #%d\n", node->id(),
1052 allocation->id()); 1083 allocation->id());
1053 } 1084 }
1054 states->LastChangedAt(node); 1085 state->LastChangedAt(node);
1055 } 1086 }
1056 } 1087 }
1057 } 1088 }
1058 1089
1059 1090
1060 Node* EscapeAnalysis::replacement(NodeId id) { 1091 Node* EscapeAnalysis::replacement(NodeId id) {
1061 if (id >= replacements_.size()) return nullptr; 1092 if (id >= replacements_.size()) return nullptr;
1062 return replacements_[id]; 1093 return replacements_[id];
1063 } 1094 }
1064 1095
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
1132 } 1163 }
1133 1164
1134 1165
1135 bool EscapeAnalysis::SetEscaped(Node* node) { 1166 bool EscapeAnalysis::SetEscaped(Node* node) {
1136 return escape_status_.SetEscaped(node); 1167 return escape_status_.SetEscaped(node);
1137 } 1168 }
1138 1169
1139 1170
1140 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { 1171 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) {
1141 if (VirtualState* states = virtual_states_[at->id()]) { 1172 if (VirtualState* states = virtual_states_[at->id()]) {
1142 return states->GetVirtualObject(id); 1173 return states->VirtualObjectFromAlias(aliases_[id]);
1143 } 1174 }
1144 return nullptr; 1175 return nullptr;
1145 } 1176 }
1146 1177
1147 1178
1148 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, 1179 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state,
1149 Node* node) { 1180 Node* node) {
1150 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); 1181 VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node));
1151 while (obj && replacement(obj->id()) && 1182 while (obj && replacement(obj->id())) {
1152 state->GetVirtualObject(replacement(obj->id()))) { 1183 if (VirtualObject* next = GetVirtualObject(state, replacement(obj->id()))) {
1153 obj = state->GetVirtualObject(replacement(obj->id())); 1184 obj = next;
1185 } else {
1186 break;
1187 }
1154 } 1188 }
1155 return obj; 1189 return obj;
1156 } 1190 }
1157 1191
1158 1192
1159 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { 1193 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) {
1160 DCHECK(IsVirtual(left) && IsVirtual(right)); 1194 DCHECK(IsVirtual(left) && IsVirtual(right));
1161 left = ResolveReplacement(left); 1195 left = ResolveReplacement(left);
1162 right = ResolveReplacement(right); 1196 right = ResolveReplacement(right);
1163 if (IsEquivalentPhi(left, right)) { 1197 if (IsEquivalentPhi(left, right)) {
(...skipping 14 matching lines...) Expand all
1178 if (FLAG_trace_turbo_escape) { 1212 if (FLAG_trace_turbo_escape) {
1179 PrintF("Load #%d from phi #%d", node->id(), from->id()); 1213 PrintF("Load #%d from phi #%d", node->id(), from->id());
1180 } 1214 }
1181 1215
1182 cache_->fields().clear(); 1216 cache_->fields().clear();
1183 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { 1217 for (int i = 0; i < node->op()->ValueInputCount(); ++i) {
1184 Node* input = NodeProperties::GetValueInput(node, i); 1218 Node* input = NodeProperties::GetValueInput(node, i);
1185 cache_->fields().push_back(input); 1219 cache_->fields().push_back(input);
1186 } 1220 }
1187 1221
1188 cache_->LoadVirtualObjectsForFieldsFrom(state); 1222 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_);
1189 if (cache_->objects().size() == cache_->fields().size()) { 1223 if (cache_->objects().size() == cache_->fields().size()) {
1190 cache_->GetFields(offset); 1224 cache_->GetFields(offset);
1191 if (cache_->fields().size() == cache_->objects().size()) { 1225 if (cache_->fields().size() == cache_->objects().size()) {
1192 Node* rep = replacement(node); 1226 Node* rep = replacement(node);
1193 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { 1227 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) {
1194 int value_input_count = static_cast<int>(cache_->fields().size()); 1228 int value_input_count = static_cast<int>(cache_->fields().size());
1195 cache_->fields().push_back(NodeProperties::GetControlInput(from)); 1229 cache_->fields().push_back(NodeProperties::GetControlInput(from));
1196 Node* phi = graph()->NewNode( 1230 Node* phi = graph()->NewNode(
1197 common()->Phi(MachineRepresentation::kTagged, value_input_count), 1231 common()->Phi(MachineRepresentation::kTagged, value_input_count),
1198 value_input_count + 1, &cache_->fields().front()); 1232 value_input_count + 1, &cache_->fields().front());
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
1380 } 1414 }
1381 } 1415 }
1382 return new_object_state; 1416 return new_object_state;
1383 } 1417 }
1384 } 1418 }
1385 } 1419 }
1386 return nullptr; 1420 return nullptr;
1387 } 1421 }
1388 1422
1389 1423
1390 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { 1424 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) {
1391 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); 1425 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(),
1426 object->field_count());
1392 for (size_t i = 0; i < object->field_count(); ++i) { 1427 for (size_t i = 0; i < object->field_count(); ++i) {
1393 if (Node* f = object->GetField(i)) { 1428 if (Node* f = object->GetField(i)) {
1394 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); 1429 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic());
1395 } 1430 }
1396 } 1431 }
1397 } 1432 }
1398 1433
1399 1434
1400 void EscapeAnalysis::DebugPrintState(VirtualState* state) { 1435 void EscapeAnalysis::DebugPrintState(VirtualState* state) {
1401 PrintF("Dumping object state %p\n", static_cast<void*>(state)); 1436 PrintF("Dumping object state %p\n", static_cast<void*>(state));
1402 for (size_t id = 0; id < state->size(); id++) { 1437 for (Alias alias = 0; alias < AliasCount(); ++alias) {
1403 if (VirtualObject* object = state->GetVirtualObject(id)) { 1438 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) {
1404 if (object->id() == id) { 1439 DebugPrintObject(object, alias);
1405 DebugPrintObject(object, static_cast<int>(id));
1406 } else {
1407 PrintF(" Object #%zu links to object #%d\n", id, object->id());
1408 }
1409 } 1440 }
1410 } 1441 }
1411 } 1442 }
1412 1443
1413 1444
1414 void EscapeAnalysis::DebugPrint() { 1445 void EscapeAnalysis::DebugPrint() {
1415 ZoneVector<VirtualState*> object_states(zone()); 1446 ZoneVector<VirtualState*> object_states(zone());
1416 for (NodeId id = 0; id < virtual_states_.size(); id++) { 1447 for (NodeId id = 0; id < virtual_states_.size(); id++) {
1417 if (VirtualState* states = virtual_states_[id]) { 1448 if (VirtualState* states = virtual_states_[id]) {
1418 if (std::find(object_states.begin(), object_states.end(), states) == 1449 if (std::find(object_states.begin(), object_states.end(), states) ==
1419 object_states.end()) { 1450 object_states.end()) {
1420 object_states.push_back(states); 1451 object_states.push_back(states);
1421 } 1452 }
1422 } 1453 }
1423 } 1454 }
1424 for (size_t n = 0; n < object_states.size(); n++) { 1455 for (size_t n = 0; n < object_states.size(); n++) {
1425 DebugPrintState(object_states[n]); 1456 DebugPrintState(object_states[n]);
1426 } 1457 }
1427 } 1458 }
1428 1459
1460
1461 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state,
1462 Node* node) {
1463 if (node->id() >= aliases_.size()) return nullptr;
1464 Alias alias = aliases_[node->id()];
1465 if (alias >= state->size()) return nullptr;
1466 return state->VirtualObjectFromAlias(alias);
1467 }
1468
1429 } // namespace compiler 1469 } // namespace compiler
1430 } // namespace internal 1470 } // namespace internal
1431 } // namespace v8 1471 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/pipeline.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698