OLD | NEW |
---|---|
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <limits> | |
6 | |
5 #include "src/compiler/escape-analysis.h" | 7 #include "src/compiler/escape-analysis.h" |
Michael Starzinger
2016/01/12 17:27:43
nit: Let's keep the "escape-analysis.h" include at
| |
6 | 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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()] = EscapeStatusFlags(status_[node->id()] & ~kOnStack); | |
Michael Starzinger
2016/01/12 17:27:43
nit: Would "status_[node->id()] &= ~kOnStack" do t
| |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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; | |
Michael Starzinger
2016/01/12 17:27:43
nit: Funny formatting, I actually like it, but V8
| |
768 default: | |
769 DCHECK_EQ(aliases_[node->id()], kUntrackable); | |
770 break; | |
771 } | |
772 for (Edge edge : node->input_edges()) { | |
773 Node* input = edge.to(); | |
774 if (aliases_[input->id()] == kNotReachable) { | |
775 stack.push_back(input); | |
776 aliases_[input->id()] = kUntrackable; | |
777 } | |
778 } | |
779 } | |
780 | |
781 if (FLAG_trace_turbo_escape) { | |
782 PrintF("Discovered trackable nodes"); | |
783 for (EscapeAnalysis::Alias id = 0; id < graph()->NodeCount(); ++id) { | |
784 if (aliases_[id] < kUntrackable) { | |
785 if (FLAG_trace_turbo_escape) { | |
786 PrintF(" #%u", id); | |
787 } | |
788 } | |
789 } | |
790 PrintF("\n"); | |
791 } | |
792 } | |
793 | |
794 | |
767 void EscapeAnalysis::RunObjectAnalysis() { | 795 void EscapeAnalysis::RunObjectAnalysis() { |
768 virtual_states_.resize(graph()->NodeCount()); | 796 virtual_states_.resize(graph()->NodeCount()); |
769 ZoneVector<Node*> stack(zone()); | 797 ZoneVector<Node*> stack(zone()); |
770 stack.push_back(graph()->start()); | 798 stack.push_back(graph()->start()); |
771 while (!stack.empty()) { | 799 while (!stack.empty()) { |
772 Node* node = stack.back(); | 800 Node* node = stack.back(); |
773 stack.pop_back(); | 801 stack.pop_back(); |
774 if (Process(node)) { | 802 if (aliases_[node->id()] != kNotReachable && Process(node)) { |
775 for (Edge edge : node->use_edges()) { | 803 for (Edge edge : node->use_edges()) { |
776 if (NodeProperties::IsEffectEdge(edge)) { | 804 if (NodeProperties::IsEffectEdge(edge)) { |
777 Node* use = edge.from(); | 805 Node* use = edge.from(); |
778 if ((use->opcode() != IrOpcode::kLoadField && | 806 if ((use->opcode() != IrOpcode::kLoadField && |
779 use->opcode() != IrOpcode::kLoadElement) || | 807 use->opcode() != IrOpcode::kLoadElement) || |
780 !IsDanglingEffectNode(use)) { | 808 !IsDanglingEffectNode(use)) { |
781 stack.push_back(use); | 809 stack.push_back(use); |
782 } | 810 } |
783 } | 811 } |
784 } | 812 } |
785 // First process loads: dangling loads are a problem otherwise. | 813 // First process loads: dangling loads are a problem otherwise. |
786 for (Edge edge : node->use_edges()) { | 814 for (Edge edge : node->use_edges()) { |
787 if (NodeProperties::IsEffectEdge(edge)) { | 815 if (NodeProperties::IsEffectEdge(edge)) { |
788 Node* use = edge.from(); | 816 Node* use = edge.from(); |
789 if ((use->opcode() == IrOpcode::kLoadField || | 817 if ((use->opcode() == IrOpcode::kLoadField || |
790 use->opcode() == IrOpcode::kLoadElement) && | 818 use->opcode() == IrOpcode::kLoadElement) && |
791 | |
792 | |
793 IsDanglingEffectNode(use)) { | 819 IsDanglingEffectNode(use)) { |
794 stack.push_back(use); | 820 stack.push_back(use); |
795 } | 821 } |
796 } | 822 } |
797 } | 823 } |
798 } | 824 } |
799 } | 825 } |
800 if (FLAG_trace_turbo_escape) { | 826 if (FLAG_trace_turbo_escape) { |
801 DebugPrint(); | 827 DebugPrint(); |
802 } | 828 } |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
912 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { | 938 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
913 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 939 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
914 node->op()->mnemonic()); | 940 node->op()->mnemonic()); |
915 UNREACHABLE(); | 941 UNREACHABLE(); |
916 } | 942 } |
917 Node* effect = NodeProperties::GetEffectInput(node); | 943 Node* effect = NodeProperties::GetEffectInput(node); |
918 // Break the cycle for effect phis. | 944 // Break the cycle for effect phis. |
919 if (effect->opcode() == IrOpcode::kEffectPhi) { | 945 if (effect->opcode() == IrOpcode::kEffectPhi) { |
920 if (virtual_states_[effect->id()] == nullptr) { | 946 if (virtual_states_[effect->id()] == nullptr) { |
921 virtual_states_[effect->id()] = | 947 virtual_states_[effect->id()] = |
922 new (zone()) VirtualState(zone(), graph()->NodeCount()); | 948 new (zone()) VirtualState(zone(), AliasCount()); |
923 } | 949 } |
924 } | 950 } |
925 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 951 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
926 if (IsEffectBranchPoint(effect)) { | 952 if (IsEffectBranchPoint(effect)) { |
927 if (FLAG_trace_turbo_escape) { | 953 if (FLAG_trace_turbo_escape) { |
928 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", | 954 PrintF("Copying object state %p from #%d (%s) to #%d (%s)\n", |
929 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 955 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
930 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 956 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
931 } | 957 } |
932 if (!virtual_states_[node->id()]) { | 958 if (!virtual_states_[node->id()]) { |
933 virtual_states_[node->id()] = | 959 virtual_states_[node->id()] = |
934 new (zone()) VirtualState(*virtual_states_[effect->id()]); | 960 new (zone()) VirtualState(*virtual_states_[effect->id()]); |
935 } else { | 961 } else { |
936 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 962 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
937 zone()); | 963 zone()); |
938 } | 964 } |
939 } else { | 965 } else { |
940 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 966 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
941 if (FLAG_trace_turbo_escape) { | 967 if (FLAG_trace_turbo_escape) { |
942 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", | 968 PrintF("Forwarding object state %p from #%d (%s) to #%d (%s)\n", |
943 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), | 969 static_cast<void*>(virtual_states_[effect->id()]), effect->id(), |
944 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); | 970 effect->op()->mnemonic(), node->id(), node->op()->mnemonic()); |
945 } | 971 } |
946 } | 972 } |
947 } | 973 } |
948 | 974 |
949 | 975 |
950 void EscapeAnalysis::ProcessStart(Node* node) { | 976 void EscapeAnalysis::ProcessStart(Node* node) { |
951 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 977 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
952 virtual_states_[node->id()] = | 978 virtual_states_[node->id()] = new (zone()) VirtualState(zone(), AliasCount()); |
953 new (zone()) VirtualState(zone(), graph()->NodeCount()); | |
954 } | 979 } |
955 | 980 |
956 | 981 |
957 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 982 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
958 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 983 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
959 bool changed = false; | 984 bool changed = false; |
960 | 985 |
961 VirtualState* mergeState = virtual_states_[node->id()]; | 986 VirtualState* mergeState = virtual_states_[node->id()]; |
962 if (!mergeState) { | 987 if (!mergeState) { |
963 mergeState = new (zone()) VirtualState(zone(), graph()->NodeCount()); | 988 mergeState = new (zone()) VirtualState(zone(), AliasCount()); |
964 virtual_states_[node->id()] = mergeState; | 989 virtual_states_[node->id()] = mergeState; |
965 changed = true; | 990 changed = true; |
966 if (FLAG_trace_turbo_escape) { | 991 if (FLAG_trace_turbo_escape) { |
967 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), | 992 PrintF("Effect Phi #%d got new states map %p.\n", node->id(), |
968 static_cast<void*>(mergeState)); | 993 static_cast<void*>(mergeState)); |
969 } | 994 } |
970 } else if (mergeState->GetLastChanged() != node) { | 995 } else if (mergeState->GetLastChanged() != node) { |
971 changed = true; | 996 changed = true; |
972 } | 997 } |
973 | 998 |
974 cache_->Clear(); | 999 cache_->Clear(); |
975 | 1000 |
976 if (FLAG_trace_turbo_escape) { | 1001 if (FLAG_trace_turbo_escape) { |
977 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), | 1002 PrintF("At Effect Phi #%d, merging states into %p:", node->id(), |
978 static_cast<void*>(mergeState)); | 1003 static_cast<void*>(mergeState)); |
979 } | 1004 } |
980 | 1005 |
981 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1006 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
982 Node* input = NodeProperties::GetEffectInput(node, i); | 1007 Node* input = NodeProperties::GetEffectInput(node, i); |
983 VirtualState* state = virtual_states_[input->id()]; | 1008 VirtualState* state = virtual_states_[input->id()]; |
984 if (state) { | 1009 if (state) { |
985 cache_->push_back(state); | 1010 cache_->states().push_back(state); |
986 } | 1011 } |
987 if (FLAG_trace_turbo_escape) { | 1012 if (FLAG_trace_turbo_escape) { |
988 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1013 PrintF(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
989 input->op()->mnemonic()); | 1014 input->op()->mnemonic()); |
990 } | 1015 } |
991 } | 1016 } |
992 if (FLAG_trace_turbo_escape) { | 1017 if (FLAG_trace_turbo_escape) { |
993 PrintF("\n"); | 1018 PrintF("\n"); |
994 } | 1019 } |
995 | 1020 |
(...skipping 15 matching lines...) Expand all Loading... | |
1011 } | 1036 } |
1012 return changed; | 1037 return changed; |
1013 } | 1038 } |
1014 | 1039 |
1015 | 1040 |
1016 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1041 void EscapeAnalysis::ProcessAllocation(Node* node) { |
1017 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1042 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
1018 ForwardVirtualState(node); | 1043 ForwardVirtualState(node); |
1019 | 1044 |
1020 // Check if we have already processed this node. | 1045 // Check if we have already processed this node. |
1021 if (virtual_states_[node->id()]->GetVirtualObject(node)) return; | 1046 if (virtual_states_[node->id()]->VirtualObjectFromAlias( |
1047 aliases_[node->id()])) { | |
1048 return; | |
1049 } | |
1022 | 1050 |
1023 NumberMatcher size(node->InputAt(0)); | 1051 NumberMatcher size(node->InputAt(0)); |
1024 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1052 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
1025 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1053 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
1026 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1054 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
1027 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1055 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
1028 if (size.HasValue()) { | 1056 if (size.HasValue()) { |
1029 virtual_states_[node->id()]->SetVirtualObject( | 1057 virtual_states_[node->id()]->SetVirtualObject( |
1030 node->id(), new (zone()) VirtualObject(node->id(), zone(), | 1058 aliases_[node->id()], |
1031 size.Value() / kPointerSize)); | 1059 new (zone()) |
1060 VirtualObject(node->id(), zone(), size.Value() / kPointerSize)); | |
1032 } else { | 1061 } else { |
1033 virtual_states_[node->id()]->SetVirtualObject( | 1062 virtual_states_[node->id()]->SetVirtualObject( |
1034 node->id(), new (zone()) VirtualObject(node->id(), zone())); | 1063 aliases_[node->id()], new (zone()) VirtualObject(node->id(), zone())); |
1035 } | 1064 } |
1036 virtual_states_[node->id()]->LastChangedAt(node); | 1065 virtual_states_[node->id()]->LastChangedAt(node); |
1037 } | 1066 } |
1038 | 1067 |
1039 | 1068 |
1040 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1069 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
1041 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1070 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
1042 ForwardVirtualState(node); | 1071 ForwardVirtualState(node); |
1043 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1072 Node* allocation = NodeProperties::GetValueInput(node, 0); |
1044 if (allocation->opcode() == IrOpcode::kAllocate) { | 1073 if (allocation->opcode() == IrOpcode::kAllocate) { |
1045 VirtualState* states = virtual_states_[node->id()]; | 1074 VirtualState* state = virtual_states_[node->id()]; |
1046 DCHECK_NOT_NULL(states->GetVirtualObject(allocation)); | 1075 if (!state->VirtualObjectFromAlias(aliases_[node->id()])) { |
1047 if (!states->GetVirtualObject(node->id())) { | 1076 VirtualObject* vobj_alloc = |
1048 states->SetVirtualObject(node->id(), | 1077 state->VirtualObjectFromAlias(aliases_[allocation->id()]); |
1049 states->GetVirtualObject(allocation)); | 1078 DCHECK_NOT_NULL(vobj_alloc); |
1079 state->SetVirtualObject(aliases_[node->id()], vobj_alloc); | |
1050 if (FLAG_trace_turbo_escape) { | 1080 if (FLAG_trace_turbo_escape) { |
1051 PrintF("Linked finish region node #%d to node #%d\n", node->id(), | 1081 PrintF("Linked finish region node #%d to node #%d\n", node->id(), |
1052 allocation->id()); | 1082 allocation->id()); |
1053 } | 1083 } |
1054 states->LastChangedAt(node); | 1084 state->LastChangedAt(node); |
1055 } | 1085 } |
1056 } | 1086 } |
1057 } | 1087 } |
1058 | 1088 |
1059 | 1089 |
1060 Node* EscapeAnalysis::replacement(NodeId id) { | 1090 Node* EscapeAnalysis::replacement(NodeId id) { |
1061 if (id >= replacements_.size()) return nullptr; | 1091 if (id >= replacements_.size()) return nullptr; |
1062 return replacements_[id]; | 1092 return replacements_[id]; |
1063 } | 1093 } |
1064 | 1094 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1132 } | 1162 } |
1133 | 1163 |
1134 | 1164 |
1135 bool EscapeAnalysis::SetEscaped(Node* node) { | 1165 bool EscapeAnalysis::SetEscaped(Node* node) { |
1136 return escape_status_.SetEscaped(node); | 1166 return escape_status_.SetEscaped(node); |
1137 } | 1167 } |
1138 | 1168 |
1139 | 1169 |
1140 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1170 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
1141 if (VirtualState* states = virtual_states_[at->id()]) { | 1171 if (VirtualState* states = virtual_states_[at->id()]) { |
1142 return states->GetVirtualObject(id); | 1172 return states->VirtualObjectFromAlias(aliases_[id]); |
1143 } | 1173 } |
1144 return nullptr; | 1174 return nullptr; |
1145 } | 1175 } |
1146 | 1176 |
1147 | 1177 |
1148 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1178 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
1149 Node* node) { | 1179 Node* node) { |
1150 VirtualObject* obj = state->GetVirtualObject(ResolveReplacement(node)); | 1180 VirtualObject* obj = GetVirtualObject(state, ResolveReplacement(node)); |
1151 while (obj && replacement(obj->id()) && | 1181 while (obj && replacement(obj->id())) { |
1152 state->GetVirtualObject(replacement(obj->id()))) { | 1182 if (VirtualObject* next = GetVirtualObject(state, replacement(obj->id()))) { |
1153 obj = state->GetVirtualObject(replacement(obj->id())); | 1183 obj = next; |
1184 } else { | |
1185 break; | |
1186 } | |
1154 } | 1187 } |
1155 return obj; | 1188 return obj; |
1156 } | 1189 } |
1157 | 1190 |
1158 | 1191 |
1159 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1192 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
1160 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1193 DCHECK(IsVirtual(left) && IsVirtual(right)); |
1161 left = ResolveReplacement(left); | 1194 left = ResolveReplacement(left); |
1162 right = ResolveReplacement(right); | 1195 right = ResolveReplacement(right); |
1163 if (IsEquivalentPhi(left, right)) { | 1196 if (IsEquivalentPhi(left, right)) { |
(...skipping 14 matching lines...) Expand all Loading... | |
1178 if (FLAG_trace_turbo_escape) { | 1211 if (FLAG_trace_turbo_escape) { |
1179 PrintF("Load #%d from phi #%d", node->id(), from->id()); | 1212 PrintF("Load #%d from phi #%d", node->id(), from->id()); |
1180 } | 1213 } |
1181 | 1214 |
1182 cache_->fields().clear(); | 1215 cache_->fields().clear(); |
1183 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1216 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
1184 Node* input = NodeProperties::GetValueInput(node, i); | 1217 Node* input = NodeProperties::GetValueInput(node, i); |
1185 cache_->fields().push_back(input); | 1218 cache_->fields().push_back(input); |
1186 } | 1219 } |
1187 | 1220 |
1188 cache_->LoadVirtualObjectsForFieldsFrom(state); | 1221 cache_->LoadVirtualObjectsForFieldsFrom(state, aliases_); |
1189 if (cache_->objects().size() == cache_->fields().size()) { | 1222 if (cache_->objects().size() == cache_->fields().size()) { |
1190 cache_->GetFields(offset); | 1223 cache_->GetFields(offset); |
1191 if (cache_->fields().size() == cache_->objects().size()) { | 1224 if (cache_->fields().size() == cache_->objects().size()) { |
1192 Node* rep = replacement(node); | 1225 Node* rep = replacement(node); |
1193 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { | 1226 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) { |
1194 int value_input_count = static_cast<int>(cache_->fields().size()); | 1227 int value_input_count = static_cast<int>(cache_->fields().size()); |
1195 cache_->fields().push_back(NodeProperties::GetControlInput(from)); | 1228 cache_->fields().push_back(NodeProperties::GetControlInput(from)); |
1196 Node* phi = graph()->NewNode( | 1229 Node* phi = graph()->NewNode( |
1197 common()->Phi(MachineRepresentation::kTagged, value_input_count), | 1230 common()->Phi(MachineRepresentation::kTagged, value_input_count), |
1198 value_input_count + 1, &cache_->fields().front()); | 1231 value_input_count + 1, &cache_->fields().front()); |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1380 } | 1413 } |
1381 } | 1414 } |
1382 return new_object_state; | 1415 return new_object_state; |
1383 } | 1416 } |
1384 } | 1417 } |
1385 } | 1418 } |
1386 return nullptr; | 1419 return nullptr; |
1387 } | 1420 } |
1388 | 1421 |
1389 | 1422 |
1390 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, NodeId id) { | 1423 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) { |
1391 PrintF(" Object #%d with %zu fields\n", id, object->field_count()); | 1424 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(), |
1425 object->field_count()); | |
1392 for (size_t i = 0; i < object->field_count(); ++i) { | 1426 for (size_t i = 0; i < object->field_count(); ++i) { |
1393 if (Node* f = object->GetField(i)) { | 1427 if (Node* f = object->GetField(i)) { |
1394 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1428 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
1395 } | 1429 } |
1396 } | 1430 } |
1397 } | 1431 } |
1398 | 1432 |
1399 | 1433 |
1400 void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 1434 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
1401 PrintF("Dumping object state %p\n", static_cast<void*>(state)); | 1435 PrintF("Dumping object state %p\n", static_cast<void*>(state)); |
1402 for (size_t id = 0; id < state->size(); id++) { | 1436 for (Alias alias = 0; alias < AliasCount(); ++alias) { |
1403 if (VirtualObject* object = state->GetVirtualObject(id)) { | 1437 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { |
1404 if (object->id() == id) { | 1438 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 } | 1439 } |
1410 } | 1440 } |
1411 } | 1441 } |
1412 | 1442 |
1413 | 1443 |
1414 void EscapeAnalysis::DebugPrint() { | 1444 void EscapeAnalysis::DebugPrint() { |
1415 ZoneVector<VirtualState*> object_states(zone()); | 1445 ZoneVector<VirtualState*> object_states(zone()); |
1416 for (NodeId id = 0; id < virtual_states_.size(); id++) { | 1446 for (NodeId id = 0; id < virtual_states_.size(); id++) { |
1417 if (VirtualState* states = virtual_states_[id]) { | 1447 if (VirtualState* states = virtual_states_[id]) { |
1418 if (std::find(object_states.begin(), object_states.end(), states) == | 1448 if (std::find(object_states.begin(), object_states.end(), states) == |
1419 object_states.end()) { | 1449 object_states.end()) { |
1420 object_states.push_back(states); | 1450 object_states.push_back(states); |
1421 } | 1451 } |
1422 } | 1452 } |
1423 } | 1453 } |
1424 for (size_t n = 0; n < object_states.size(); n++) { | 1454 for (size_t n = 0; n < object_states.size(); n++) { |
1425 DebugPrintState(object_states[n]); | 1455 DebugPrintState(object_states[n]); |
1426 } | 1456 } |
1427 } | 1457 } |
1428 | 1458 |
1459 | |
1460 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, | |
1461 Node* node) { | |
1462 if (node->id() >= aliases_.size()) return nullptr; | |
1463 Alias alias = aliases_[node->id()]; | |
1464 if (alias >= state->size()) return nullptr; | |
1465 return state->VirtualObjectFromAlias(alias); | |
1466 } | |
1467 | |
1429 } // namespace compiler | 1468 } // namespace compiler |
1430 } // namespace internal | 1469 } // namespace internal |
1431 } // namespace v8 | 1470 } // namespace v8 |
OLD | NEW |