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 "src/compiler/escape-analysis.h" | 5 #include "src/compiler/escape-analysis.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/base/flags.h" | 9 #include "src/base/flags.h" |
10 #include "src/bootstrapper.h" | 10 #include "src/bootstrapper.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 } while (false) | 33 } while (false) |
34 #else | 34 #else |
35 #define TRACE(...) | 35 #define TRACE(...) |
36 #endif | 36 #endif |
37 | 37 |
38 const Alias EscapeStatusAnalysis::kNotReachable = | 38 const Alias EscapeStatusAnalysis::kNotReachable = |
39 std::numeric_limits<Alias>::max(); | 39 std::numeric_limits<Alias>::max(); |
40 const Alias EscapeStatusAnalysis::kUntrackable = | 40 const Alias EscapeStatusAnalysis::kUntrackable = |
41 std::numeric_limits<Alias>::max() - 1; | 41 std::numeric_limits<Alias>::max() - 1; |
42 | 42 |
43 | |
44 class VirtualObject : public ZoneObject { | 43 class VirtualObject : public ZoneObject { |
45 public: | 44 public: |
46 enum Status { | 45 enum Status { |
47 kInitial = 0, | 46 kInitial = 0, |
48 kTracked = 1u << 0, | 47 kTracked = 1u << 0, |
49 kInitialized = 1u << 1, | 48 kInitialized = 1u << 1, |
50 kCopyRequired = 1u << 2, | 49 kCopyRequired = 1u << 2, |
51 }; | 50 }; |
52 typedef base::Flags<Status, unsigned char> StatusFlags; | 51 typedef base::Flags<Status, unsigned char> StatusFlags; |
53 | 52 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 NodeId id_; | 134 NodeId id_; |
136 StatusFlags status_; | 135 StatusFlags status_; |
137 ZoneVector<Node*> fields_; | 136 ZoneVector<Node*> fields_; |
138 ZoneVector<bool> phi_; | 137 ZoneVector<bool> phi_; |
139 Node* object_state_; | 138 Node* object_state_; |
140 VirtualState* owner_; | 139 VirtualState* owner_; |
141 | 140 |
142 DISALLOW_COPY_AND_ASSIGN(VirtualObject); | 141 DISALLOW_COPY_AND_ASSIGN(VirtualObject); |
143 }; | 142 }; |
144 | 143 |
145 | |
146 DEFINE_OPERATORS_FOR_FLAGS(VirtualObject::StatusFlags) | 144 DEFINE_OPERATORS_FOR_FLAGS(VirtualObject::StatusFlags) |
147 | 145 |
148 | |
149 bool VirtualObject::UpdateFrom(const VirtualObject& other) { | 146 bool VirtualObject::UpdateFrom(const VirtualObject& other) { |
150 bool changed = status_ != other.status_; | 147 bool changed = status_ != other.status_; |
151 status_ = other.status_; | 148 status_ = other.status_; |
152 phi_ = other.phi_; | 149 phi_ = other.phi_; |
153 if (fields_.size() != other.fields_.size()) { | 150 if (fields_.size() != other.fields_.size()) { |
154 fields_ = other.fields_; | 151 fields_ = other.fields_; |
155 return true; | 152 return true; |
156 } | 153 } |
157 for (size_t i = 0; i < fields_.size(); ++i) { | 154 for (size_t i = 0; i < fields_.size(); ++i) { |
158 if (fields_[i] != other.fields_[i]) { | 155 if (fields_[i] != other.fields_[i]) { |
159 changed = true; | 156 changed = true; |
160 fields_[i] = other.fields_[i]; | 157 fields_[i] = other.fields_[i]; |
161 } | 158 } |
162 } | 159 } |
163 return changed; | 160 return changed; |
164 } | 161 } |
165 | 162 |
166 | |
167 class VirtualState : public ZoneObject { | 163 class VirtualState : public ZoneObject { |
168 public: | 164 public: |
169 VirtualState(NodeId owner, Zone* zone, size_t size); | 165 VirtualState(Node* owner, Zone* zone, size_t size) |
170 VirtualState(NodeId owner, const VirtualState& states); | 166 : info_(size, nullptr, zone), owner_(owner) {} |
| 167 |
| 168 VirtualState(Node* owner, const VirtualState& state) |
| 169 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), |
| 170 owner_(owner) { |
| 171 for (size_t i = 0; i < info_.size(); ++i) { |
| 172 if (state.info_[i]) { |
| 173 info_[i] = state.info_[i]; |
| 174 } |
| 175 } |
| 176 } |
171 | 177 |
172 VirtualObject* VirtualObjectFromAlias(size_t alias); | 178 VirtualObject* VirtualObjectFromAlias(size_t alias); |
173 VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, | 179 VirtualObject* GetOrCreateTrackedVirtualObject(Alias alias, NodeId id, |
174 size_t fields, | 180 size_t fields, |
175 bool initialized, Zone* zone, | 181 bool initialized, Zone* zone, |
176 bool force_copy); | 182 bool force_copy); |
177 void SetVirtualObject(Alias alias, VirtualObject* state); | 183 void SetVirtualObject(Alias alias, VirtualObject* state); |
178 bool UpdateFrom(VirtualState* state, Zone* zone); | 184 bool UpdateFrom(VirtualState* state, Zone* zone); |
179 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 185 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
180 CommonOperatorBuilder* common, Node* control, int arity); | 186 CommonOperatorBuilder* common, Node* control, int arity); |
181 size_t size() const { return info_.size(); } | 187 size_t size() const { return info_.size(); } |
182 NodeId owner() const { return owner_; } | 188 Node* owner() const { return owner_; } |
183 VirtualObject* Copy(VirtualObject* obj, Alias alias); | 189 VirtualObject* Copy(VirtualObject* obj, Alias alias); |
184 void SetCopyRequired() { | 190 void SetCopyRequired() { |
185 for (VirtualObject* obj : info_) { | 191 for (VirtualObject* obj : info_) { |
186 if (obj) obj->SetCopyRequired(); | 192 if (obj) obj->SetCopyRequired(); |
187 } | 193 } |
188 } | 194 } |
189 | 195 |
190 private: | 196 private: |
191 ZoneVector<VirtualObject*> info_; | 197 ZoneVector<VirtualObject*> info_; |
192 NodeId owner_; | 198 Node* owner_; |
193 | 199 |
194 DISALLOW_COPY_AND_ASSIGN(VirtualState); | 200 DISALLOW_COPY_AND_ASSIGN(VirtualState); |
195 }; | 201 }; |
196 | 202 |
197 | |
198 class MergeCache : public ZoneObject { | 203 class MergeCache : public ZoneObject { |
199 public: | 204 public: |
200 explicit MergeCache(Zone* zone) | 205 explicit MergeCache(Zone* zone) |
201 : states_(zone), objects_(zone), fields_(zone) { | 206 : states_(zone), objects_(zone), fields_(zone) { |
202 states_.reserve(5); | 207 states_.reserve(5); |
203 objects_.reserve(5); | 208 objects_.reserve(5); |
204 fields_.reserve(5); | 209 fields_.reserve(5); |
205 } | 210 } |
206 ZoneVector<VirtualState*>& states() { return states_; } | 211 ZoneVector<VirtualState*>& states() { return states_; } |
207 ZoneVector<VirtualObject*>& objects() { return objects_; } | 212 ZoneVector<VirtualObject*>& objects() { return objects_; } |
208 ZoneVector<Node*>& fields() { return fields_; } | 213 ZoneVector<Node*>& fields() { return fields_; } |
209 void Clear() { | 214 void Clear() { |
210 states_.clear(); | 215 states_.clear(); |
211 objects_.clear(); | 216 objects_.clear(); |
212 fields_.clear(); | 217 fields_.clear(); |
213 } | 218 } |
214 size_t LoadVirtualObjectsFromStatesFor(Alias alias); | 219 size_t LoadVirtualObjectsFromStatesFor(Alias alias); |
215 void LoadVirtualObjectsForFieldsFrom(VirtualState* state, | 220 void LoadVirtualObjectsForFieldsFrom(VirtualState* state, |
216 const ZoneVector<Alias>& aliases); | 221 const ZoneVector<Alias>& aliases); |
217 Node* GetFields(size_t pos); | 222 Node* GetFields(size_t pos); |
218 | 223 |
219 private: | 224 private: |
220 ZoneVector<VirtualState*> states_; | 225 ZoneVector<VirtualState*> states_; |
221 ZoneVector<VirtualObject*> objects_; | 226 ZoneVector<VirtualObject*> objects_; |
222 ZoneVector<Node*> fields_; | 227 ZoneVector<Node*> fields_; |
223 | 228 |
224 DISALLOW_COPY_AND_ASSIGN(MergeCache); | 229 DISALLOW_COPY_AND_ASSIGN(MergeCache); |
225 }; | 230 }; |
226 | 231 |
227 | |
228 size_t MergeCache::LoadVirtualObjectsFromStatesFor(Alias alias) { | 232 size_t MergeCache::LoadVirtualObjectsFromStatesFor(Alias alias) { |
229 objects_.clear(); | 233 objects_.clear(); |
230 DCHECK_GT(states_.size(), 0u); | 234 DCHECK_GT(states_.size(), 0u); |
231 size_t min = std::numeric_limits<size_t>::max(); | 235 size_t min = std::numeric_limits<size_t>::max(); |
232 for (VirtualState* state : states_) { | 236 for (VirtualState* state : states_) { |
233 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { | 237 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
234 objects_.push_back(obj); | 238 objects_.push_back(obj); |
235 min = std::min(obj->field_count(), min); | 239 min = std::min(obj->field_count(), min); |
236 } | 240 } |
237 } | 241 } |
238 return min; | 242 return min; |
239 } | 243 } |
240 | 244 |
241 | |
242 void MergeCache::LoadVirtualObjectsForFieldsFrom( | 245 void MergeCache::LoadVirtualObjectsForFieldsFrom( |
243 VirtualState* state, const ZoneVector<Alias>& aliases) { | 246 VirtualState* state, const ZoneVector<Alias>& aliases) { |
244 objects_.clear(); | 247 objects_.clear(); |
245 size_t max_alias = state->size(); | 248 size_t max_alias = state->size(); |
246 for (Node* field : fields_) { | 249 for (Node* field : fields_) { |
247 Alias alias = aliases[field->id()]; | 250 Alias alias = aliases[field->id()]; |
248 if (alias >= max_alias) continue; | 251 if (alias >= max_alias) continue; |
249 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { | 252 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { |
250 objects_.push_back(obj); | 253 objects_.push_back(obj); |
251 } | 254 } |
252 } | 255 } |
253 } | 256 } |
254 | 257 |
255 | |
256 Node* MergeCache::GetFields(size_t pos) { | 258 Node* MergeCache::GetFields(size_t pos) { |
257 fields_.clear(); | 259 fields_.clear(); |
258 Node* rep = pos >= objects_.front()->field_count() | 260 Node* rep = pos >= objects_.front()->field_count() |
259 ? nullptr | 261 ? nullptr |
260 : objects_.front()->GetField(pos); | 262 : objects_.front()->GetField(pos); |
261 for (VirtualObject* obj : objects_) { | 263 for (VirtualObject* obj : objects_) { |
262 if (pos >= obj->field_count()) continue; | 264 if (pos >= obj->field_count()) continue; |
263 Node* field = obj->GetField(pos); | 265 Node* field = obj->GetField(pos); |
264 if (field) { | 266 if (field) { |
265 fields_.push_back(field); | 267 fields_.push_back(field); |
266 } | 268 } |
267 if (field != rep) { | 269 if (field != rep) { |
268 rep = nullptr; | 270 rep = nullptr; |
269 } | 271 } |
270 } | 272 } |
271 return rep; | 273 return rep; |
272 } | 274 } |
273 | 275 |
274 | |
275 VirtualState::VirtualState(NodeId owner, Zone* zone, size_t size) | |
276 : info_(size, nullptr, zone), owner_(owner) {} | |
277 | |
278 | |
279 VirtualState::VirtualState(NodeId owner, const VirtualState& state) | |
280 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()), | |
281 owner_(owner) { | |
282 for (size_t i = 0; i < info_.size(); ++i) { | |
283 if (state.info_[i]) { | |
284 info_[i] = state.info_[i]; | |
285 } | |
286 } | |
287 } | |
288 | |
289 | |
290 VirtualObject* VirtualState::Copy(VirtualObject* obj, Alias alias) { | 276 VirtualObject* VirtualState::Copy(VirtualObject* obj, Alias alias) { |
291 if (obj->owner() == this) return obj; | 277 if (obj->owner() == this) return obj; |
292 VirtualObject* new_obj = | 278 VirtualObject* new_obj = |
293 new (info_.get_allocator().zone()) VirtualObject(this, *obj); | 279 new (info_.get_allocator().zone()) VirtualObject(this, *obj); |
294 TRACE("At state %p, alias @%d (#%d), copying virtual object from %p to %p\n", | 280 TRACE("At state %p, alias @%d (#%d), copying virtual object from %p to %p\n", |
295 static_cast<void*>(this), alias, obj->id(), static_cast<void*>(obj), | 281 static_cast<void*>(this), alias, obj->id(), static_cast<void*>(obj), |
296 static_cast<void*>(new_obj)); | 282 static_cast<void*>(new_obj)); |
297 info_[alias] = new_obj; | 283 info_[alias] = new_obj; |
298 return new_obj; | 284 return new_obj; |
299 } | 285 } |
300 | 286 |
301 | |
302 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { | 287 VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { |
303 return info_[alias]; | 288 return info_[alias]; |
304 } | 289 } |
305 | 290 |
306 | |
307 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( | 291 VirtualObject* VirtualState::GetOrCreateTrackedVirtualObject( |
308 Alias alias, NodeId id, size_t field_number, bool initialized, Zone* zone, | 292 Alias alias, NodeId id, size_t field_number, bool initialized, Zone* zone, |
309 bool force_copy) { | 293 bool force_copy) { |
310 if (!force_copy) { | 294 if (!force_copy) { |
311 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { | 295 if (VirtualObject* obj = VirtualObjectFromAlias(alias)) { |
312 return obj; | 296 return obj; |
313 } | 297 } |
314 } | 298 } |
315 VirtualObject* obj = new (zone) VirtualObject(id, this, zone, 0, initialized); | 299 VirtualObject* obj = new (zone) VirtualObject(id, this, zone, 0, initialized); |
316 SetVirtualObject(alias, obj); | 300 SetVirtualObject(alias, obj); |
317 return obj; | 301 return obj; |
318 } | 302 } |
319 | 303 |
320 | |
321 void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { | 304 void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { |
322 info_[alias] = obj; | 305 info_[alias] = obj; |
323 } | 306 } |
324 | 307 |
325 | |
326 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { | 308 bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { |
327 if (from == this) return false; | 309 if (from == this) return false; |
328 bool changed = false; | 310 bool changed = false; |
329 for (Alias alias = 0; alias < size(); ++alias) { | 311 for (Alias alias = 0; alias < size(); ++alias) { |
330 VirtualObject* ls = VirtualObjectFromAlias(alias); | 312 VirtualObject* ls = VirtualObjectFromAlias(alias); |
331 VirtualObject* rs = from->VirtualObjectFromAlias(alias); | 313 VirtualObject* rs = from->VirtualObjectFromAlias(alias); |
332 | 314 |
333 if (ls == rs || rs == nullptr) continue; | 315 if (ls == rs || rs == nullptr) continue; |
334 | 316 |
335 if (ls == nullptr) { | 317 if (ls == nullptr) { |
336 ls = new (zone) VirtualObject(this, *rs); | 318 ls = new (zone) VirtualObject(this, *rs); |
337 SetVirtualObject(alias, ls); | 319 SetVirtualObject(alias, ls); |
338 changed = true; | 320 changed = true; |
339 continue; | 321 continue; |
340 } | 322 } |
341 | 323 |
342 TRACE(" Updating fields of @%d\n", alias); | 324 TRACE(" Updating fields of @%d\n", alias); |
343 | 325 |
344 changed = ls->UpdateFrom(*rs) || changed; | 326 changed = ls->UpdateFrom(*rs) || changed; |
345 } | 327 } |
346 return false; | 328 return false; |
347 } | 329 } |
348 | 330 |
349 | |
350 namespace { | 331 namespace { |
351 | 332 |
352 bool IsEquivalentPhi(Node* node1, Node* node2) { | 333 bool IsEquivalentPhi(Node* node1, Node* node2) { |
353 if (node1 == node2) return true; | 334 if (node1 == node2) return true; |
354 if (node1->opcode() != IrOpcode::kPhi || node2->opcode() != IrOpcode::kPhi || | 335 if (node1->opcode() != IrOpcode::kPhi || node2->opcode() != IrOpcode::kPhi || |
355 node1->op()->ValueInputCount() != node2->op()->ValueInputCount()) { | 336 node1->op()->ValueInputCount() != node2->op()->ValueInputCount()) { |
356 return false; | 337 return false; |
357 } | 338 } |
358 for (int i = 0; i < node1->op()->ValueInputCount(); ++i) { | 339 for (int i = 0; i < node1->op()->ValueInputCount(); ++i) { |
359 Node* input1 = NodeProperties::GetValueInput(node1, i); | 340 Node* input1 = NodeProperties::GetValueInput(node1, i); |
360 Node* input2 = NodeProperties::GetValueInput(node2, i); | 341 Node* input2 = NodeProperties::GetValueInput(node2, i); |
361 if (!IsEquivalentPhi(input1, input2)) { | 342 if (!IsEquivalentPhi(input1, input2)) { |
362 return false; | 343 return false; |
363 } | 344 } |
364 } | 345 } |
365 return true; | 346 return true; |
366 } | 347 } |
367 | 348 |
368 | |
369 bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) { | 349 bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) { |
370 if (phi->opcode() != IrOpcode::kPhi) return false; | 350 if (phi->opcode() != IrOpcode::kPhi) return false; |
371 if (phi->op()->ValueInputCount() != inputs.size()) { | 351 if (phi->op()->ValueInputCount() != inputs.size()) { |
372 return false; | 352 return false; |
373 } | 353 } |
374 for (size_t i = 0; i < inputs.size(); ++i) { | 354 for (size_t i = 0; i < inputs.size(); ++i) { |
375 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i)); | 355 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i)); |
376 if (!IsEquivalentPhi(input, inputs[i])) { | 356 if (!IsEquivalentPhi(input, inputs[i])) { |
377 return false; | 357 return false; |
378 } | 358 } |
379 } | 359 } |
380 return true; | 360 return true; |
381 } | 361 } |
382 | 362 |
383 } // namespace | 363 } // namespace |
384 | 364 |
385 | |
386 Node* EscapeAnalysis::GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) { | 365 Node* EscapeAnalysis::GetReplacementIfSame(ZoneVector<VirtualObject*>& objs) { |
387 Node* rep = GetReplacement(objs.front()->id()); | 366 Node* rep = GetReplacement(objs.front()->id()); |
388 for (VirtualObject* obj : objs) { | 367 for (VirtualObject* obj : objs) { |
389 if (GetReplacement(obj->id()) != rep) { | 368 if (GetReplacement(obj->id()) != rep) { |
390 return nullptr; | 369 return nullptr; |
391 } | 370 } |
392 } | 371 } |
393 return rep; | 372 return rep; |
394 } | 373 } |
395 | 374 |
396 | |
397 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 375 bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, |
398 CommonOperatorBuilder* common, Node* control, | 376 CommonOperatorBuilder* common, Node* control, |
399 int arity) { | 377 int arity) { |
400 DCHECK_GT(cache->states().size(), 0u); | 378 DCHECK_GT(cache->states().size(), 0u); |
401 bool changed = false; | 379 bool changed = false; |
402 for (Alias alias = 0; alias < size(); ++alias) { | 380 for (Alias alias = 0; alias < size(); ++alias) { |
403 cache->objects().clear(); | 381 cache->objects().clear(); |
404 VirtualObject* mergeObject = VirtualObjectFromAlias(alias); | 382 VirtualObject* mergeObject = VirtualObjectFromAlias(alias); |
405 bool copy_merge_object = false; | 383 bool copy_merge_object = false; |
406 size_t fields = std::numeric_limits<size_t>::max(); | 384 size_t fields = std::numeric_limits<size_t>::max(); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 if (mergeObject) { | 458 if (mergeObject) { |
481 TRACE(" Alias %d, virtual object removed\n", alias); | 459 TRACE(" Alias %d, virtual object removed\n", alias); |
482 changed = true; | 460 changed = true; |
483 } | 461 } |
484 SetVirtualObject(alias, nullptr); | 462 SetVirtualObject(alias, nullptr); |
485 } | 463 } |
486 } | 464 } |
487 return changed; | 465 return changed; |
488 } | 466 } |
489 | 467 |
490 | |
491 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 468 EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, |
492 Graph* graph, Zone* zone) | 469 Graph* graph, Zone* zone) |
493 : stack_(zone), | 470 : stack_(zone), |
494 object_analysis_(object_analysis), | 471 object_analysis_(object_analysis), |
495 graph_(graph), | 472 graph_(graph), |
496 zone_(zone), | 473 zone_(zone), |
497 status_(graph->NodeCount(), kUnknown, zone), | 474 status_(graph->NodeCount(), kUnknown, zone), |
498 next_free_alias_(0), | 475 next_free_alias_(0), |
499 status_stack_(zone), | 476 status_stack_(zone), |
500 aliases_(zone) {} | 477 aliases_(zone) {} |
501 | 478 |
502 | |
503 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} | 479 EscapeStatusAnalysis::~EscapeStatusAnalysis() {} |
504 | 480 |
505 | |
506 bool EscapeStatusAnalysis::HasEntry(Node* node) { | 481 bool EscapeStatusAnalysis::HasEntry(Node* node) { |
507 return status_[node->id()] & (kTracked | kEscaped); | 482 return status_[node->id()] & (kTracked | kEscaped); |
508 } | 483 } |
509 | 484 |
510 | |
511 bool EscapeStatusAnalysis::IsVirtual(Node* node) { | 485 bool EscapeStatusAnalysis::IsVirtual(Node* node) { |
512 return IsVirtual(node->id()); | 486 return IsVirtual(node->id()); |
513 } | 487 } |
514 | 488 |
515 | |
516 bool EscapeStatusAnalysis::IsVirtual(NodeId id) { | 489 bool EscapeStatusAnalysis::IsVirtual(NodeId id) { |
517 return (status_[id] & kTracked) && !(status_[id] & kEscaped); | 490 return (status_[id] & kTracked) && !(status_[id] & kEscaped); |
518 } | 491 } |
519 | 492 |
520 | |
521 bool EscapeStatusAnalysis::IsEscaped(Node* node) { | 493 bool EscapeStatusAnalysis::IsEscaped(Node* node) { |
522 return status_[node->id()] & kEscaped; | 494 return status_[node->id()] & kEscaped; |
523 } | 495 } |
524 | 496 |
525 | |
526 bool EscapeStatusAnalysis::IsAllocation(Node* node) { | 497 bool EscapeStatusAnalysis::IsAllocation(Node* node) { |
527 return node->opcode() == IrOpcode::kAllocate || | 498 return node->opcode() == IrOpcode::kAllocate || |
528 node->opcode() == IrOpcode::kFinishRegion; | 499 node->opcode() == IrOpcode::kFinishRegion; |
529 } | 500 } |
530 | 501 |
531 | |
532 bool EscapeStatusAnalysis::SetEscaped(Node* node) { | 502 bool EscapeStatusAnalysis::SetEscaped(Node* node) { |
533 bool changed = !(status_[node->id()] & kEscaped); | 503 bool changed = !(status_[node->id()] & kEscaped); |
534 status_[node->id()] |= kEscaped | kTracked; | 504 status_[node->id()] |= kEscaped | kTracked; |
535 return changed; | 505 return changed; |
536 } | 506 } |
537 | 507 |
| 508 bool EscapeStatusAnalysis::IsInQueue(NodeId id) { |
| 509 return status_[id] & kInQueue; |
| 510 } |
| 511 |
| 512 void EscapeStatusAnalysis::SetInQueue(NodeId id, bool on_stack) { |
| 513 if (on_stack) { |
| 514 status_[id] |= kInQueue; |
| 515 } else { |
| 516 status_[id] &= ~kInQueue; |
| 517 } |
| 518 } |
538 | 519 |
539 void EscapeStatusAnalysis::ResizeStatusVector() { | 520 void EscapeStatusAnalysis::ResizeStatusVector() { |
540 if (status_.size() <= graph()->NodeCount()) { | 521 if (status_.size() <= graph()->NodeCount()) { |
541 status_.resize(graph()->NodeCount() * 1.1, kUnknown); | 522 status_.resize(graph()->NodeCount() * 1.1, kUnknown); |
542 } | 523 } |
543 } | 524 } |
544 | 525 |
545 | |
546 size_t EscapeStatusAnalysis::GetStatusVectorSize() { return status_.size(); } | 526 size_t EscapeStatusAnalysis::GetStatusVectorSize() { return status_.size(); } |
547 | 527 |
548 | |
549 void EscapeStatusAnalysis::RunStatusAnalysis() { | 528 void EscapeStatusAnalysis::RunStatusAnalysis() { |
550 ResizeStatusVector(); | 529 ResizeStatusVector(); |
551 while (!status_stack_.empty()) { | 530 while (!status_stack_.empty()) { |
552 Node* node = status_stack_.back(); | 531 Node* node = status_stack_.back(); |
553 status_stack_.pop_back(); | 532 status_stack_.pop_back(); |
554 status_[node->id()] &= ~kOnStack; | 533 status_[node->id()] &= ~kOnStack; |
555 Process(node); | 534 Process(node); |
556 status_[node->id()] |= kVisited; | 535 status_[node->id()] |= kVisited; |
557 } | 536 } |
558 } | 537 } |
559 | 538 |
560 | |
561 void EscapeStatusAnalysis::EnqueueForStatusAnalysis(Node* node) { | 539 void EscapeStatusAnalysis::EnqueueForStatusAnalysis(Node* node) { |
562 DCHECK_NOT_NULL(node); | 540 DCHECK_NOT_NULL(node); |
563 if (!(status_[node->id()] & kOnStack)) { | 541 if (!(status_[node->id()] & kOnStack)) { |
564 status_stack_.push_back(node); | 542 status_stack_.push_back(node); |
565 status_[node->id()] |= kOnStack; | 543 status_[node->id()] |= kOnStack; |
566 } | 544 } |
567 } | 545 } |
568 | 546 |
569 | |
570 void EscapeStatusAnalysis::RevisitInputs(Node* node) { | 547 void EscapeStatusAnalysis::RevisitInputs(Node* node) { |
571 for (Edge edge : node->input_edges()) { | 548 for (Edge edge : node->input_edges()) { |
572 Node* input = edge.to(); | 549 Node* input = edge.to(); |
573 if (!(status_[input->id()] & kOnStack)) { | 550 if (!(status_[input->id()] & kOnStack)) { |
574 status_stack_.push_back(input); | 551 status_stack_.push_back(input); |
575 status_[input->id()] |= kOnStack; | 552 status_[input->id()] |= kOnStack; |
576 } | 553 } |
577 } | 554 } |
578 } | 555 } |
579 | 556 |
580 | |
581 void EscapeStatusAnalysis::RevisitUses(Node* node) { | 557 void EscapeStatusAnalysis::RevisitUses(Node* node) { |
582 for (Edge edge : node->use_edges()) { | 558 for (Edge edge : node->use_edges()) { |
583 Node* use = edge.from(); | 559 Node* use = edge.from(); |
584 if (!(status_[use->id()] & kOnStack) && !IsNotReachable(use)) { | 560 if (!(status_[use->id()] & kOnStack) && !IsNotReachable(use)) { |
585 status_stack_.push_back(use); | 561 status_stack_.push_back(use); |
586 status_[use->id()] |= kOnStack; | 562 status_[use->id()] |= kOnStack; |
587 } | 563 } |
588 } | 564 } |
589 } | 565 } |
590 | 566 |
591 | |
592 void EscapeStatusAnalysis::Process(Node* node) { | 567 void EscapeStatusAnalysis::Process(Node* node) { |
593 switch (node->opcode()) { | 568 switch (node->opcode()) { |
594 case IrOpcode::kAllocate: | 569 case IrOpcode::kAllocate: |
595 ProcessAllocate(node); | 570 ProcessAllocate(node); |
596 break; | 571 break; |
597 case IrOpcode::kFinishRegion: | 572 case IrOpcode::kFinishRegion: |
598 ProcessFinishRegion(node); | 573 ProcessFinishRegion(node); |
599 break; | 574 break; |
600 case IrOpcode::kStoreField: | 575 case IrOpcode::kStoreField: |
601 ProcessStoreField(node); | 576 ProcessStoreField(node); |
(...skipping 20 matching lines...) Expand all Loading... |
622 if (!IsAllocationPhi(node) && SetEscaped(node)) { | 597 if (!IsAllocationPhi(node) && SetEscaped(node)) { |
623 RevisitInputs(node); | 598 RevisitInputs(node); |
624 RevisitUses(node); | 599 RevisitUses(node); |
625 } | 600 } |
626 CheckUsesForEscape(node); | 601 CheckUsesForEscape(node); |
627 default: | 602 default: |
628 break; | 603 break; |
629 } | 604 } |
630 } | 605 } |
631 | 606 |
632 | |
633 bool EscapeStatusAnalysis::IsAllocationPhi(Node* node) { | 607 bool EscapeStatusAnalysis::IsAllocationPhi(Node* node) { |
634 for (Edge edge : node->input_edges()) { | 608 for (Edge edge : node->input_edges()) { |
635 Node* input = edge.to(); | 609 Node* input = edge.to(); |
636 if (input->opcode() == IrOpcode::kPhi && !IsEscaped(input)) continue; | 610 if (input->opcode() == IrOpcode::kPhi && !IsEscaped(input)) continue; |
637 if (IsAllocation(input)) continue; | 611 if (IsAllocation(input)) continue; |
638 return false; | 612 return false; |
639 } | 613 } |
640 return true; | 614 return true; |
641 } | 615 } |
642 | 616 |
643 | |
644 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { | 617 void EscapeStatusAnalysis::ProcessStoreField(Node* node) { |
645 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 618 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
646 Node* to = NodeProperties::GetValueInput(node, 0); | 619 Node* to = NodeProperties::GetValueInput(node, 0); |
647 Node* val = NodeProperties::GetValueInput(node, 1); | 620 Node* val = NodeProperties::GetValueInput(node, 1); |
648 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { | 621 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { |
649 RevisitUses(val); | 622 RevisitUses(val); |
650 RevisitInputs(val); | 623 RevisitInputs(val); |
651 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", | 624 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", |
652 val->id(), val->op()->mnemonic(), to->id()); | 625 val->id(), val->op()->mnemonic(), to->id()); |
653 } | 626 } |
654 } | 627 } |
655 | 628 |
656 | |
657 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) { | 629 void EscapeStatusAnalysis::ProcessStoreElement(Node* node) { |
658 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 630 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
659 Node* to = NodeProperties::GetValueInput(node, 0); | 631 Node* to = NodeProperties::GetValueInput(node, 0); |
660 Node* val = NodeProperties::GetValueInput(node, 2); | 632 Node* val = NodeProperties::GetValueInput(node, 2); |
661 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { | 633 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) { |
662 RevisitUses(val); | 634 RevisitUses(val); |
663 RevisitInputs(val); | 635 RevisitInputs(val); |
664 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", | 636 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", |
665 val->id(), val->op()->mnemonic(), to->id()); | 637 val->id(), val->op()->mnemonic(), to->id()); |
666 } | 638 } |
667 } | 639 } |
668 | 640 |
669 | |
670 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 641 void EscapeStatusAnalysis::ProcessAllocate(Node* node) { |
671 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 642 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
672 if (!HasEntry(node)) { | 643 if (!HasEntry(node)) { |
673 status_[node->id()] |= kTracked; | 644 status_[node->id()] |= kTracked; |
674 TRACE("Created status entry for node #%d (%s)\n", node->id(), | 645 TRACE("Created status entry for node #%d (%s)\n", node->id(), |
675 node->op()->mnemonic()); | 646 node->op()->mnemonic()); |
676 NumberMatcher size(node->InputAt(0)); | 647 NumberMatcher size(node->InputAt(0)); |
677 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 648 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
678 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 649 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
679 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 650 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
680 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 651 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
681 RevisitUses(node); | 652 RevisitUses(node); |
682 if (!size.HasValue() && SetEscaped(node)) { | 653 if (!size.HasValue() && SetEscaped(node)) { |
683 TRACE("Setting #%d to escaped because of non-const alloc\n", node->id()); | 654 TRACE("Setting #%d to escaped because of non-const alloc\n", node->id()); |
684 // This node is already known to escape, uses do not have to be checked | 655 // This node is already known to escape, uses do not have to be checked |
685 // for escape. | 656 // for escape. |
686 return; | 657 return; |
687 } | 658 } |
688 } | 659 } |
689 if (CheckUsesForEscape(node, true)) { | 660 if (CheckUsesForEscape(node, true)) { |
690 RevisitUses(node); | 661 RevisitUses(node); |
691 } | 662 } |
692 } | 663 } |
693 | 664 |
694 | |
695 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, | 665 bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, |
696 bool phi_escaping) { | 666 bool phi_escaping) { |
697 for (Edge edge : uses->use_edges()) { | 667 for (Edge edge : uses->use_edges()) { |
698 Node* use = edge.from(); | 668 Node* use = edge.from(); |
699 if (IsNotReachable(use)) continue; | 669 if (IsNotReachable(use)) continue; |
700 if (edge.index() >= use->op()->ValueInputCount() + | 670 if (edge.index() >= use->op()->ValueInputCount() + |
701 OperatorProperties::GetContextInputCount(use->op())) | 671 OperatorProperties::GetContextInputCount(use->op())) |
702 continue; | 672 continue; |
703 switch (use->opcode()) { | 673 switch (use->opcode()) { |
704 case IrOpcode::kPhi: | 674 case IrOpcode::kPhi: |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n", | 725 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n", |
756 rep->id(), rep->op()->mnemonic(), use->id(), | 726 rep->id(), rep->op()->mnemonic(), use->id(), |
757 use->op()->mnemonic()); | 727 use->op()->mnemonic()); |
758 return true; | 728 return true; |
759 } | 729 } |
760 } | 730 } |
761 } | 731 } |
762 return false; | 732 return false; |
763 } | 733 } |
764 | 734 |
765 | |
766 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { | 735 void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) { |
767 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 736 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
768 if (!HasEntry(node)) { | 737 if (!HasEntry(node)) { |
769 status_[node->id()] |= kTracked; | 738 status_[node->id()] |= kTracked; |
770 RevisitUses(node); | 739 RevisitUses(node); |
771 } | 740 } |
772 if (CheckUsesForEscape(node, true)) { | 741 if (CheckUsesForEscape(node, true)) { |
773 RevisitInputs(node); | 742 RevisitInputs(node); |
774 } | 743 } |
775 } | 744 } |
776 | 745 |
777 | |
778 void EscapeStatusAnalysis::DebugPrint() { | 746 void EscapeStatusAnalysis::DebugPrint() { |
779 for (NodeId id = 0; id < status_.size(); id++) { | 747 for (NodeId id = 0; id < status_.size(); id++) { |
780 if (status_[id] & kTracked) { | 748 if (status_[id] & kTracked) { |
781 PrintF("Node #%d is %s\n", id, | 749 PrintF("Node #%d is %s\n", id, |
782 (status_[id] & kEscaped) ? "escaping" : "virtual"); | 750 (status_[id] & kEscaped) ? "escaping" : "virtual"); |
783 } | 751 } |
784 } | 752 } |
785 } | 753 } |
786 | 754 |
787 | |
788 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 755 EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, |
789 Zone* zone) | 756 Zone* zone) |
790 : status_analysis_(this, graph, zone), | 757 : status_analysis_(this, graph, zone), |
791 common_(common), | 758 common_(common), |
792 virtual_states_(zone), | 759 virtual_states_(zone), |
793 replacements_(zone), | 760 replacements_(zone), |
794 cache_(new (zone) MergeCache(zone)) {} | 761 cache_(new (zone) MergeCache(zone)) {} |
795 | 762 |
796 | |
797 EscapeAnalysis::~EscapeAnalysis() {} | 763 EscapeAnalysis::~EscapeAnalysis() {} |
798 | 764 |
799 | |
800 void EscapeAnalysis::Run() { | 765 void EscapeAnalysis::Run() { |
801 replacements_.resize(graph()->NodeCount()); | 766 replacements_.resize(graph()->NodeCount()); |
802 status_analysis_.AssignAliases(); | 767 status_analysis_.AssignAliases(); |
803 if (status_analysis_.AliasCount() == 0) return; | 768 if (status_analysis_.AliasCount() == 0) return; |
804 status_analysis_.ResizeStatusVector(); | 769 status_analysis_.ResizeStatusVector(); |
805 RunObjectAnalysis(); | 770 RunObjectAnalysis(); |
806 status_analysis_.RunStatusAnalysis(); | 771 status_analysis_.RunStatusAnalysis(); |
807 } | 772 } |
808 | 773 |
809 | |
810 void EscapeStatusAnalysis::AssignAliases() { | 774 void EscapeStatusAnalysis::AssignAliases() { |
811 stack_.reserve(graph()->NodeCount() * 0.2); | 775 stack_.reserve(graph()->NodeCount() * 0.2); |
812 ResizeStatusVector(); | 776 ResizeStatusVector(); |
813 stack_.push_back(graph()->end()); | 777 stack_.push_back(graph()->end()); |
814 CHECK_LT(graph()->NodeCount(), kUntrackable); | 778 CHECK_LT(graph()->NodeCount(), kUntrackable); |
815 aliases_.resize(graph()->NodeCount(), kNotReachable); | 779 aliases_.resize(graph()->NodeCount(), kNotReachable); |
816 aliases_[graph()->end()->id()] = kUntrackable; | 780 aliases_[graph()->end()->id()] = kUntrackable; |
817 status_stack_.reserve(8); | 781 status_stack_.reserve(8); |
818 TRACE("Discovering trackable nodes"); | 782 TRACE("Discovering trackable nodes"); |
819 while (!stack_.empty()) { | 783 while (!stack_.empty()) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 Node* input = edge.to(); | 824 Node* input = edge.to(); |
861 if (aliases_[input->id()] == kNotReachable) { | 825 if (aliases_[input->id()] == kNotReachable) { |
862 stack_.push_back(input); | 826 stack_.push_back(input); |
863 aliases_[input->id()] = kUntrackable; | 827 aliases_[input->id()] = kUntrackable; |
864 } | 828 } |
865 } | 829 } |
866 } | 830 } |
867 TRACE("\n"); | 831 TRACE("\n"); |
868 } | 832 } |
869 | 833 |
870 | |
871 bool EscapeStatusAnalysis::IsNotReachable(Node* node) { | 834 bool EscapeStatusAnalysis::IsNotReachable(Node* node) { |
872 if (node->id() >= aliases_.size()) { | 835 if (node->id() >= aliases_.size()) { |
873 return false; | 836 return false; |
874 } | 837 } |
875 return aliases_[node->id()] == kNotReachable; | 838 return aliases_[node->id()] == kNotReachable; |
876 } | 839 } |
877 | 840 |
878 | |
879 void EscapeAnalysis::RunObjectAnalysis() { | 841 void EscapeAnalysis::RunObjectAnalysis() { |
880 virtual_states_.resize(graph()->NodeCount()); | 842 virtual_states_.resize(graph()->NodeCount()); |
881 stack().push_back(graph()->start()); | 843 ZoneDeque<Node*> queue(zone()); |
| 844 queue.push_back(graph()->start()); |
882 ZoneVector<Node*> danglers(zone()); | 845 ZoneVector<Node*> danglers(zone()); |
883 while (!stack().empty()) { | 846 while (!queue.empty()) { |
884 Node* node = stack().back(); | 847 Node* node = queue.back(); |
885 stack().pop_back(); | 848 queue.pop_back(); |
| 849 status_analysis_.SetInQueue(node->id(), false); |
886 if (Process(node)) { | 850 if (Process(node)) { |
887 for (Edge edge : node->use_edges()) { | 851 for (Edge edge : node->use_edges()) { |
888 Node* use = edge.from(); | 852 Node* use = edge.from(); |
889 if (IsNotReachable(use)) { | 853 if (IsNotReachable(use)) { |
890 continue; | 854 continue; |
891 } | 855 } |
892 if (NodeProperties::IsEffectEdge(edge)) { | 856 if (NodeProperties::IsEffectEdge(edge)) { |
893 if ((use->opcode() != IrOpcode::kLoadField && | 857 // Iteration order: depth first, but delay phis. |
894 use->opcode() != IrOpcode::kLoadElement) || | 858 // We need DFS do avoid some duplication of VirtualStates and |
895 !IsDanglingEffectNode(use)) { | 859 // VirtualObjects, and we want to delay phis to improve performance. |
896 stack().push_back(use); | 860 if (use->opcode() == IrOpcode::kEffectPhi) { |
| 861 if (!status_analysis_.IsInQueue(use->id())) { |
| 862 queue.push_front(use); |
| 863 } |
| 864 } else if ((use->opcode() != IrOpcode::kLoadField && |
| 865 use->opcode() != IrOpcode::kLoadElement) || |
| 866 !IsDanglingEffectNode(use)) { |
| 867 if (!status_analysis_.IsInQueue(use->id())) { |
| 868 status_analysis_.SetInQueue(use->id(), true); |
| 869 queue.push_back(use); |
| 870 } |
897 } else { | 871 } else { |
898 danglers.push_back(use); | 872 danglers.push_back(use); |
899 } | 873 } |
900 } | 874 } |
901 } | 875 } |
902 stack().insert(stack().end(), danglers.begin(), danglers.end()); | 876 // Danglers need to be processed immediately, even if they are |
| 877 // on the stack. Since they do not have effect outputs, |
| 878 // we don't have to track whether they are on the stack. |
| 879 queue.insert(queue.end(), danglers.begin(), danglers.end()); |
903 danglers.clear(); | 880 danglers.clear(); |
904 } | 881 } |
905 } | 882 } |
906 #ifdef DEBUG | 883 #ifdef DEBUG |
907 if (FLAG_trace_turbo_escape) { | 884 if (FLAG_trace_turbo_escape) { |
908 DebugPrint(); | 885 DebugPrint(); |
909 } | 886 } |
910 #endif | 887 #endif |
911 } | 888 } |
912 | 889 |
913 | |
914 bool EscapeStatusAnalysis::IsDanglingEffectNode(Node* node) { | 890 bool EscapeStatusAnalysis::IsDanglingEffectNode(Node* node) { |
915 if (status_[node->id()] & kDanglingComputed) { | 891 if (status_[node->id()] & kDanglingComputed) { |
916 return status_[node->id()] & kDangling; | 892 return status_[node->id()] & kDangling; |
917 } | 893 } |
918 if (node->op()->EffectInputCount() == 0 || | 894 if (node->op()->EffectInputCount() == 0 || |
919 node->op()->EffectOutputCount() == 0 || | 895 node->op()->EffectOutputCount() == 0 || |
920 (node->op()->EffectInputCount() == 1 && | 896 (node->op()->EffectInputCount() == 1 && |
921 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart)) { | 897 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart)) { |
922 // The start node is used as sentinel for nodes that are in general | 898 // The start node is used as sentinel for nodes that are in general |
923 // effectful, but of which an analysis has determined that they do not | 899 // effectful, but of which an analysis has determined that they do not |
924 // produce effects in this instance. We don't consider these nodes dangling. | 900 // produce effects in this instance. We don't consider these nodes dangling. |
925 status_[node->id()] |= kDanglingComputed; | 901 status_[node->id()] |= kDanglingComputed; |
926 return false; | 902 return false; |
927 } | 903 } |
928 for (Edge edge : node->use_edges()) { | 904 for (Edge edge : node->use_edges()) { |
929 Node* use = edge.from(); | 905 Node* use = edge.from(); |
930 if (aliases_[use->id()] == kNotReachable) continue; | 906 if (aliases_[use->id()] == kNotReachable) continue; |
931 if (NodeProperties::IsEffectEdge(edge)) { | 907 if (NodeProperties::IsEffectEdge(edge)) { |
932 status_[node->id()] |= kDanglingComputed; | 908 status_[node->id()] |= kDanglingComputed; |
933 return false; | 909 return false; |
934 } | 910 } |
935 } | 911 } |
936 status_[node->id()] |= kDanglingComputed | kDangling; | 912 status_[node->id()] |= kDanglingComputed | kDangling; |
937 return true; | 913 return true; |
938 } | 914 } |
939 | 915 |
940 | |
941 bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) { | 916 bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) { |
942 if (status_[node->id()] & kBranchPointComputed) { | 917 if (status_[node->id()] & kBranchPointComputed) { |
943 return status_[node->id()] & kBranchPoint; | 918 return status_[node->id()] & kBranchPoint; |
944 } | 919 } |
945 int count = 0; | 920 int count = 0; |
946 for (Edge edge : node->use_edges()) { | 921 for (Edge edge : node->use_edges()) { |
947 Node* use = edge.from(); | 922 Node* use = edge.from(); |
948 if (aliases_[use->id()] == kNotReachable) continue; | 923 if (aliases_[use->id()] == kNotReachable) continue; |
949 if (NodeProperties::IsEffectEdge(edge)) { | 924 if (NodeProperties::IsEffectEdge(edge)) { |
950 if ((use->opcode() == IrOpcode::kLoadField || | 925 if ((use->opcode() == IrOpcode::kLoadField || |
951 use->opcode() == IrOpcode::kLoadElement || | 926 use->opcode() == IrOpcode::kLoadElement || |
952 use->opcode() == IrOpcode::kLoad) && | 927 use->opcode() == IrOpcode::kLoad) && |
953 IsDanglingEffectNode(use)) | 928 IsDanglingEffectNode(use)) |
954 continue; | 929 continue; |
955 if (++count > 1) { | 930 if (++count > 1) { |
956 status_[node->id()] |= kBranchPointComputed | kBranchPoint; | 931 status_[node->id()] |= kBranchPointComputed | kBranchPoint; |
957 return true; | 932 return true; |
958 } | 933 } |
959 } | 934 } |
960 } | 935 } |
961 status_[node->id()] |= kBranchPointComputed; | 936 status_[node->id()] |= kBranchPointComputed; |
962 return false; | 937 return false; |
963 } | 938 } |
964 | 939 |
965 | |
966 bool EscapeAnalysis::Process(Node* node) { | 940 bool EscapeAnalysis::Process(Node* node) { |
967 switch (node->opcode()) { | 941 switch (node->opcode()) { |
968 case IrOpcode::kAllocate: | 942 case IrOpcode::kAllocate: |
969 ProcessAllocation(node); | 943 ProcessAllocation(node); |
970 break; | 944 break; |
971 case IrOpcode::kBeginRegion: | 945 case IrOpcode::kBeginRegion: |
972 ForwardVirtualState(node); | 946 ForwardVirtualState(node); |
973 break; | 947 break; |
974 case IrOpcode::kFinishRegion: | 948 case IrOpcode::kFinishRegion: |
975 ProcessFinishRegion(node); | 949 ProcessFinishRegion(node); |
(...skipping 19 matching lines...) Expand all Loading... |
995 default: | 969 default: |
996 if (node->op()->EffectInputCount() > 0) { | 970 if (node->op()->EffectInputCount() > 0) { |
997 ForwardVirtualState(node); | 971 ForwardVirtualState(node); |
998 } | 972 } |
999 ProcessAllocationUsers(node); | 973 ProcessAllocationUsers(node); |
1000 break; | 974 break; |
1001 } | 975 } |
1002 return true; | 976 return true; |
1003 } | 977 } |
1004 | 978 |
1005 | |
1006 void EscapeAnalysis::ProcessAllocationUsers(Node* node) { | 979 void EscapeAnalysis::ProcessAllocationUsers(Node* node) { |
1007 for (Edge edge : node->input_edges()) { | 980 for (Edge edge : node->input_edges()) { |
1008 Node* input = edge.to(); | 981 Node* input = edge.to(); |
1009 Node* use = edge.from(); | 982 Node* use = edge.from(); |
1010 if (edge.index() >= use->op()->ValueInputCount() + | 983 if (edge.index() >= use->op()->ValueInputCount() + |
1011 OperatorProperties::GetContextInputCount(use->op())) | 984 OperatorProperties::GetContextInputCount(use->op())) |
1012 continue; | 985 continue; |
1013 switch (node->opcode()) { | 986 switch (node->opcode()) { |
1014 case IrOpcode::kStoreField: | 987 case IrOpcode::kStoreField: |
1015 case IrOpcode::kLoadField: | 988 case IrOpcode::kLoadField: |
(...skipping 13 matching lines...) Expand all Loading... |
1029 obj->ClearAllFields(); | 1002 obj->ClearAllFields(); |
1030 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), | 1003 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), |
1031 obj->id()); | 1004 obj->id()); |
1032 } | 1005 } |
1033 } | 1006 } |
1034 break; | 1007 break; |
1035 } | 1008 } |
1036 } | 1009 } |
1037 } | 1010 } |
1038 | 1011 |
1039 | |
1040 VirtualState* EscapeAnalysis::CopyForModificationAt(VirtualState* state, | 1012 VirtualState* EscapeAnalysis::CopyForModificationAt(VirtualState* state, |
1041 Node* node) { | 1013 Node* node) { |
1042 if (state->owner() != node->id()) { | 1014 if (state->owner() != node) { |
1043 VirtualState* new_state = new (zone()) VirtualState(node->id(), *state); | 1015 VirtualState* new_state = new (zone()) VirtualState(node, *state); |
1044 virtual_states_[node->id()] = new_state; | 1016 virtual_states_[node->id()] = new_state; |
1045 TRACE("Copying virtual state %p to new state %p at node %s#%d\n", | 1017 TRACE("Copying virtual state %p to new state %p at node %s#%d\n", |
1046 static_cast<void*>(state), static_cast<void*>(new_state), | 1018 static_cast<void*>(state), static_cast<void*>(new_state), |
1047 node->op()->mnemonic(), node->id()); | 1019 node->op()->mnemonic(), node->id()); |
1048 return new_state; | 1020 return new_state; |
1049 } | 1021 } |
1050 return state; | 1022 return state; |
1051 } | 1023 } |
1052 | 1024 |
1053 | |
1054 VirtualObject* EscapeAnalysis::CopyForModificationAt(VirtualObject* obj, | 1025 VirtualObject* EscapeAnalysis::CopyForModificationAt(VirtualObject* obj, |
1055 VirtualState* state, | 1026 VirtualState* state, |
1056 Node* node) { | 1027 Node* node) { |
1057 if (obj->NeedCopyForModification()) { | 1028 if (obj->NeedCopyForModification()) { |
1058 state = CopyForModificationAt(state, node); | 1029 state = CopyForModificationAt(state, node); |
1059 return state->Copy(obj, GetAlias(obj->id())); | 1030 return state->Copy(obj, GetAlias(obj->id())); |
1060 } | 1031 } |
1061 return obj; | 1032 return obj; |
1062 } | 1033 } |
1063 | 1034 |
1064 | |
1065 void EscapeAnalysis::ForwardVirtualState(Node* node) { | 1035 void EscapeAnalysis::ForwardVirtualState(Node* node) { |
1066 DCHECK_EQ(node->op()->EffectInputCount(), 1); | 1036 DCHECK_EQ(node->op()->EffectInputCount(), 1); |
1067 #ifdef DEBUG | 1037 #ifdef DEBUG |
1068 if (node->opcode() != IrOpcode::kLoadField && | 1038 if (node->opcode() != IrOpcode::kLoadField && |
1069 node->opcode() != IrOpcode::kLoadElement && | 1039 node->opcode() != IrOpcode::kLoadElement && |
1070 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { | 1040 node->opcode() != IrOpcode::kLoad && IsDanglingEffectNode(node)) { |
1071 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 1041 PrintF("Dangeling effect node: #%d (%s)\n", node->id(), |
1072 node->op()->mnemonic()); | 1042 node->op()->mnemonic()); |
1073 UNREACHABLE(); | 1043 UNREACHABLE(); |
1074 } | 1044 } |
1075 #endif // DEBUG | 1045 #endif // DEBUG |
1076 Node* effect = NodeProperties::GetEffectInput(node); | 1046 Node* effect = NodeProperties::GetEffectInput(node); |
1077 // Break the cycle for effect phis. | 1047 // Break the cycle for effect phis. |
1078 if (effect->opcode() == IrOpcode::kEffectPhi && | 1048 if (effect->opcode() == IrOpcode::kEffectPhi && |
1079 virtual_states_[effect->id()] == nullptr) { | 1049 virtual_states_[effect->id()] == nullptr) { |
1080 VirtualState* state = | 1050 VirtualState* state = |
1081 new (zone()) VirtualState(effect->id(), zone(), AliasCount()); | 1051 new (zone()) VirtualState(effect, zone(), AliasCount()); |
1082 virtual_states_[effect->id()] = state; | 1052 virtual_states_[effect->id()] = state; |
1083 TRACE("Effect Phi #%d got new virtual state %p.\n", effect->id(), | 1053 TRACE("Effect Phi #%d got new virtual state %p.\n", effect->id(), |
1084 static_cast<void*>(virtual_states_[effect->id()])); | 1054 static_cast<void*>(virtual_states_[effect->id()])); |
1085 } | 1055 } |
1086 DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 1056 DCHECK_NOT_NULL(virtual_states_[effect->id()]); |
1087 if (virtual_states_[node->id()]) { | 1057 if (virtual_states_[node->id()]) { |
1088 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 1058 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], |
1089 zone()); | 1059 zone()); |
1090 } else { | 1060 } else { |
1091 virtual_states_[node->id()] = virtual_states_[effect->id()]; | 1061 virtual_states_[node->id()] = virtual_states_[effect->id()]; |
1092 TRACE("Forwarding object state %p from %s#%d to %s#%d", | 1062 TRACE("Forwarding object state %p from %s#%d to %s#%d", |
1093 static_cast<void*>(virtual_states_[effect->id()]), | 1063 static_cast<void*>(virtual_states_[effect->id()]), |
1094 effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), | 1064 effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(), |
1095 node->id()); | 1065 node->id()); |
1096 if (IsEffectBranchPoint(effect) || | 1066 if (IsEffectBranchPoint(effect) || |
1097 OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { | 1067 OperatorProperties::GetFrameStateInputCount(node->op()) > 0) { |
1098 virtual_states_[node->id()]->SetCopyRequired(); | 1068 virtual_states_[node->id()]->SetCopyRequired(); |
1099 TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), | 1069 TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(), |
1100 effect->id()); | 1070 effect->id()); |
1101 } | 1071 } |
1102 TRACE("\n"); | 1072 TRACE("\n"); |
1103 } | 1073 } |
1104 } | 1074 } |
1105 | 1075 |
1106 | |
1107 void EscapeAnalysis::ProcessStart(Node* node) { | 1076 void EscapeAnalysis::ProcessStart(Node* node) { |
1108 DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 1077 DCHECK_EQ(node->opcode(), IrOpcode::kStart); |
1109 virtual_states_[node->id()] = | 1078 virtual_states_[node->id()] = |
1110 new (zone()) VirtualState(node->id(), zone(), AliasCount()); | 1079 new (zone()) VirtualState(node, zone(), AliasCount()); |
1111 } | 1080 } |
1112 | 1081 |
1113 | |
1114 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { | 1082 bool EscapeAnalysis::ProcessEffectPhi(Node* node) { |
1115 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); | 1083 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi); |
1116 bool changed = false; | 1084 bool changed = false; |
1117 | 1085 |
1118 VirtualState* mergeState = virtual_states_[node->id()]; | 1086 VirtualState* mergeState = virtual_states_[node->id()]; |
1119 if (!mergeState) { | 1087 if (!mergeState) { |
1120 mergeState = new (zone()) VirtualState(node->id(), zone(), AliasCount()); | 1088 mergeState = new (zone()) VirtualState(node, zone(), AliasCount()); |
1121 virtual_states_[node->id()] = mergeState; | 1089 virtual_states_[node->id()] = mergeState; |
1122 changed = true; | 1090 changed = true; |
1123 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), | 1091 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), |
1124 static_cast<void*>(mergeState)); | 1092 static_cast<void*>(mergeState)); |
1125 } | 1093 } |
1126 | 1094 |
1127 cache_->Clear(); | 1095 cache_->Clear(); |
1128 | 1096 |
1129 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), | 1097 TRACE("At Effect Phi #%d, merging states into %p:", node->id(), |
1130 static_cast<void*>(mergeState)); | 1098 static_cast<void*>(mergeState)); |
1131 | 1099 |
1132 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { | 1100 for (int i = 0; i < node->op()->EffectInputCount(); ++i) { |
1133 Node* input = NodeProperties::GetEffectInput(node, i); | 1101 Node* input = NodeProperties::GetEffectInput(node, i); |
1134 VirtualState* state = virtual_states_[input->id()]; | 1102 VirtualState* state = virtual_states_[input->id()]; |
1135 if (state) { | 1103 if (state) { |
1136 cache_->states().push_back(state); | 1104 cache_->states().push_back(state); |
1137 if (state == mergeState) { | 1105 if (state == mergeState) { |
1138 mergeState = | 1106 mergeState = new (zone()) VirtualState(node, zone(), AliasCount()); |
1139 new (zone()) VirtualState(node->id(), zone(), AliasCount()); | |
1140 virtual_states_[node->id()] = mergeState; | 1107 virtual_states_[node->id()] = mergeState; |
1141 changed = true; | 1108 changed = true; |
1142 } | 1109 } |
1143 } | 1110 } |
1144 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 1111 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), |
1145 input->op()->mnemonic()); | 1112 input->op()->mnemonic()); |
1146 } | 1113 } |
1147 TRACE("\n"); | 1114 TRACE("\n"); |
1148 | 1115 |
1149 if (cache_->states().size() == 0) { | 1116 if (cache_->states().size() == 0) { |
1150 return changed; | 1117 return changed; |
1151 } | 1118 } |
1152 | 1119 |
1153 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), | 1120 changed = mergeState->MergeFrom(cache_, zone(), graph(), common(), |
1154 NodeProperties::GetControlInput(node), | 1121 NodeProperties::GetControlInput(node), |
1155 node->op()->EffectInputCount()) || | 1122 node->op()->EffectInputCount()) || |
1156 changed; | 1123 changed; |
1157 | 1124 |
1158 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); | 1125 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); |
1159 | 1126 |
1160 if (changed) { | 1127 if (changed) { |
1161 status_analysis_.ResizeStatusVector(); | 1128 status_analysis_.ResizeStatusVector(); |
1162 } | 1129 } |
1163 return changed; | 1130 return changed; |
1164 } | 1131 } |
1165 | 1132 |
1166 | |
1167 void EscapeAnalysis::ProcessAllocation(Node* node) { | 1133 void EscapeAnalysis::ProcessAllocation(Node* node) { |
1168 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 1134 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); |
1169 ForwardVirtualState(node); | 1135 ForwardVirtualState(node); |
1170 VirtualState* state = virtual_states_[node->id()]; | 1136 VirtualState* state = virtual_states_[node->id()]; |
1171 Alias alias = GetAlias(node->id()); | 1137 Alias alias = GetAlias(node->id()); |
1172 | 1138 |
1173 // Check if we have already processed this node. | 1139 // Check if we have already processed this node. |
1174 if (state->VirtualObjectFromAlias(alias)) { | 1140 if (state->VirtualObjectFromAlias(alias)) { |
1175 return; | 1141 return; |
1176 } | 1142 } |
1177 | 1143 |
1178 state = CopyForModificationAt(state, node); | 1144 if (state->owner()->opcode() == IrOpcode::kEffectPhi) { |
| 1145 state = CopyForModificationAt(state, node); |
| 1146 } |
1179 | 1147 |
1180 NumberMatcher size(node->InputAt(0)); | 1148 NumberMatcher size(node->InputAt(0)); |
1181 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && | 1149 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant && |
1182 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && | 1150 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant && |
1183 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && | 1151 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant && |
1184 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); | 1152 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant); |
1185 if (size.HasValue()) { | 1153 if (size.HasValue()) { |
1186 state->SetVirtualObject( | 1154 VirtualObject* obj = new (zone()) VirtualObject( |
1187 alias, new (zone()) VirtualObject(node->id(), state, zone(), | 1155 node->id(), state, zone(), size.Value() / kPointerSize, false); |
1188 size.Value() / kPointerSize, false)); | 1156 state->SetVirtualObject(alias, obj); |
1189 } else { | 1157 } else { |
1190 state->SetVirtualObject( | 1158 state->SetVirtualObject( |
1191 alias, new (zone()) VirtualObject(node->id(), state, zone())); | 1159 alias, new (zone()) VirtualObject(node->id(), state, zone())); |
1192 } | 1160 } |
1193 } | 1161 } |
1194 | 1162 |
1195 | |
1196 void EscapeAnalysis::ProcessFinishRegion(Node* node) { | 1163 void EscapeAnalysis::ProcessFinishRegion(Node* node) { |
1197 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); | 1164 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion); |
1198 ForwardVirtualState(node); | 1165 ForwardVirtualState(node); |
1199 Node* allocation = NodeProperties::GetValueInput(node, 0); | 1166 Node* allocation = NodeProperties::GetValueInput(node, 0); |
1200 if (allocation->opcode() == IrOpcode::kAllocate) { | 1167 if (allocation->opcode() == IrOpcode::kAllocate) { |
1201 VirtualState* state = virtual_states_[node->id()]; | 1168 VirtualState* state = virtual_states_[node->id()]; |
1202 VirtualObject* obj = state->VirtualObjectFromAlias(GetAlias(node->id())); | 1169 VirtualObject* obj = state->VirtualObjectFromAlias(GetAlias(node->id())); |
1203 DCHECK_NOT_NULL(obj); | 1170 DCHECK_NOT_NULL(obj); |
1204 obj->SetInitialized(); | 1171 obj->SetInitialized(); |
1205 } | 1172 } |
1206 } | 1173 } |
1207 | 1174 |
1208 | |
1209 Node* EscapeAnalysis::replacement(NodeId id) { | 1175 Node* EscapeAnalysis::replacement(NodeId id) { |
1210 if (id >= replacements_.size()) return nullptr; | 1176 if (id >= replacements_.size()) return nullptr; |
1211 return replacements_[id]; | 1177 return replacements_[id]; |
1212 } | 1178 } |
1213 | 1179 |
1214 | |
1215 Node* EscapeAnalysis::replacement(Node* node) { | 1180 Node* EscapeAnalysis::replacement(Node* node) { |
1216 return replacement(node->id()); | 1181 return replacement(node->id()); |
1217 } | 1182 } |
1218 | 1183 |
1219 | |
1220 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { | 1184 bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { |
1221 bool changed = replacements_[node->id()] != rep; | 1185 bool changed = replacements_[node->id()] != rep; |
1222 replacements_[node->id()] = rep; | 1186 replacements_[node->id()] = rep; |
1223 return changed; | 1187 return changed; |
1224 } | 1188 } |
1225 | 1189 |
1226 | |
1227 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, | 1190 bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, |
1228 Node* rep) { | 1191 Node* rep) { |
1229 if (SetReplacement(node, rep)) { | 1192 if (SetReplacement(node, rep)) { |
1230 if (rep) { | 1193 if (rep) { |
1231 TRACE("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), | 1194 TRACE("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(), |
1232 rep->op()->mnemonic()); | 1195 rep->op()->mnemonic()); |
1233 } else { | 1196 } else { |
1234 TRACE("Replacement of #%d cleared\n", node->id()); | 1197 TRACE("Replacement of #%d cleared\n", node->id()); |
1235 } | 1198 } |
1236 return true; | 1199 return true; |
1237 } | 1200 } |
1238 return false; | 1201 return false; |
1239 } | 1202 } |
1240 | 1203 |
1241 | |
1242 Node* EscapeAnalysis::ResolveReplacement(Node* node) { | 1204 Node* EscapeAnalysis::ResolveReplacement(Node* node) { |
1243 while (replacement(node)) { | 1205 while (replacement(node)) { |
1244 node = replacement(node); | 1206 node = replacement(node); |
1245 } | 1207 } |
1246 return node; | 1208 return node; |
1247 } | 1209 } |
1248 | 1210 |
1249 | |
1250 Node* EscapeAnalysis::GetReplacement(Node* node) { | 1211 Node* EscapeAnalysis::GetReplacement(Node* node) { |
1251 return GetReplacement(node->id()); | 1212 return GetReplacement(node->id()); |
1252 } | 1213 } |
1253 | 1214 |
1254 | |
1255 Node* EscapeAnalysis::GetReplacement(NodeId id) { | 1215 Node* EscapeAnalysis::GetReplacement(NodeId id) { |
1256 Node* node = nullptr; | 1216 Node* node = nullptr; |
1257 while (replacement(id)) { | 1217 while (replacement(id)) { |
1258 node = replacement(id); | 1218 node = replacement(id); |
1259 id = node->id(); | 1219 id = node->id(); |
1260 } | 1220 } |
1261 return node; | 1221 return node; |
1262 } | 1222 } |
1263 | 1223 |
1264 | |
1265 bool EscapeAnalysis::IsVirtual(Node* node) { | 1224 bool EscapeAnalysis::IsVirtual(Node* node) { |
1266 if (node->id() >= status_analysis_.GetStatusVectorSize()) { | 1225 if (node->id() >= status_analysis_.GetStatusVectorSize()) { |
1267 return false; | 1226 return false; |
1268 } | 1227 } |
1269 return status_analysis_.IsVirtual(node); | 1228 return status_analysis_.IsVirtual(node); |
1270 } | 1229 } |
1271 | 1230 |
1272 | |
1273 bool EscapeAnalysis::IsEscaped(Node* node) { | 1231 bool EscapeAnalysis::IsEscaped(Node* node) { |
1274 if (node->id() >= status_analysis_.GetStatusVectorSize()) { | 1232 if (node->id() >= status_analysis_.GetStatusVectorSize()) { |
1275 return false; | 1233 return false; |
1276 } | 1234 } |
1277 return status_analysis_.IsEscaped(node); | 1235 return status_analysis_.IsEscaped(node); |
1278 } | 1236 } |
1279 | 1237 |
1280 | |
1281 bool EscapeAnalysis::SetEscaped(Node* node) { | 1238 bool EscapeAnalysis::SetEscaped(Node* node) { |
1282 return status_analysis_.SetEscaped(node); | 1239 return status_analysis_.SetEscaped(node); |
1283 } | 1240 } |
1284 | 1241 |
1285 | |
1286 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { | 1242 VirtualObject* EscapeAnalysis::GetVirtualObject(Node* at, NodeId id) { |
1287 if (VirtualState* states = virtual_states_[at->id()]) { | 1243 if (VirtualState* states = virtual_states_[at->id()]) { |
1288 return states->VirtualObjectFromAlias(GetAlias(id)); | 1244 return states->VirtualObjectFromAlias(GetAlias(id)); |
1289 } | 1245 } |
1290 return nullptr; | 1246 return nullptr; |
1291 } | 1247 } |
1292 | 1248 |
1293 | |
1294 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, | 1249 VirtualObject* EscapeAnalysis::ResolveVirtualObject(VirtualState* state, |
1295 Node* node) { | 1250 Node* node) { |
1296 return GetVirtualObject(state, ResolveReplacement(node)); | 1251 return GetVirtualObject(state, ResolveReplacement(node)); |
1297 } | 1252 } |
1298 | 1253 |
1299 | |
1300 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { | 1254 bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) { |
1301 DCHECK(IsVirtual(left) && IsVirtual(right)); | 1255 DCHECK(IsVirtual(left) && IsVirtual(right)); |
1302 left = ResolveReplacement(left); | 1256 left = ResolveReplacement(left); |
1303 right = ResolveReplacement(right); | 1257 right = ResolveReplacement(right); |
1304 if (IsEquivalentPhi(left, right)) { | 1258 if (IsEquivalentPhi(left, right)) { |
1305 return true; | 1259 return true; |
1306 } | 1260 } |
1307 return false; | 1261 return false; |
1308 } | 1262 } |
1309 | 1263 |
1310 | |
1311 int EscapeAnalysis::OffsetFromAccess(Node* node) { | 1264 int EscapeAnalysis::OffsetFromAccess(Node* node) { |
1312 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 1265 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); |
1313 return OpParameter<FieldAccess>(node).offset / kPointerSize; | 1266 return OpParameter<FieldAccess>(node).offset / kPointerSize; |
1314 } | 1267 } |
1315 | 1268 |
1316 | |
1317 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, | 1269 void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* node, |
1318 VirtualState* state) { | 1270 VirtualState* state) { |
1319 TRACE("Load #%d from phi #%d", node->id(), from->id()); | 1271 TRACE("Load #%d from phi #%d", node->id(), from->id()); |
1320 | 1272 |
1321 cache_->fields().clear(); | 1273 cache_->fields().clear(); |
1322 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { | 1274 for (int i = 0; i < node->op()->ValueInputCount(); ++i) { |
1323 Node* input = NodeProperties::GetValueInput(node, i); | 1275 Node* input = NodeProperties::GetValueInput(node, i); |
1324 cache_->fields().push_back(input); | 1276 cache_->fields().push_back(input); |
1325 } | 1277 } |
1326 | 1278 |
(...skipping 16 matching lines...) Expand all Loading... |
1343 TRACE(" has already phi #%d.\n", rep->id()); | 1295 TRACE(" has already phi #%d.\n", rep->id()); |
1344 } | 1296 } |
1345 } else { | 1297 } else { |
1346 TRACE(" has incomplete field info.\n"); | 1298 TRACE(" has incomplete field info.\n"); |
1347 } | 1299 } |
1348 } else { | 1300 } else { |
1349 TRACE(" has incomplete virtual object info.\n"); | 1301 TRACE(" has incomplete virtual object info.\n"); |
1350 } | 1302 } |
1351 } | 1303 } |
1352 | 1304 |
1353 | |
1354 void EscapeAnalysis::ProcessLoadField(Node* node) { | 1305 void EscapeAnalysis::ProcessLoadField(Node* node) { |
1355 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 1306 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); |
1356 ForwardVirtualState(node); | 1307 ForwardVirtualState(node); |
1357 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1308 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1358 VirtualState* state = virtual_states_[node->id()]; | 1309 VirtualState* state = virtual_states_[node->id()]; |
1359 if (VirtualObject* object = GetVirtualObject(state, from)) { | 1310 if (VirtualObject* object = GetVirtualObject(state, from)) { |
1360 int offset = OffsetFromAccess(node); | 1311 int offset = OffsetFromAccess(node); |
1361 if (!object->IsTracked() || | 1312 if (!object->IsTracked() || |
1362 static_cast<size_t>(offset) >= object->field_count()) { | 1313 static_cast<size_t>(offset) >= object->field_count()) { |
1363 return; | 1314 return; |
1364 } | 1315 } |
1365 Node* value = object->GetField(offset); | 1316 Node* value = object->GetField(offset); |
1366 if (value) { | 1317 if (value) { |
1367 value = ResolveReplacement(value); | 1318 value = ResolveReplacement(value); |
1368 } | 1319 } |
1369 // Record that the load has this alias. | 1320 // Record that the load has this alias. |
1370 UpdateReplacement(state, node, value); | 1321 UpdateReplacement(state, node, value); |
1371 } else if (from->opcode() == IrOpcode::kPhi && | 1322 } else if (from->opcode() == IrOpcode::kPhi && |
1372 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { | 1323 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) { |
1373 int offset = OffsetFromAccess(node); | 1324 int offset = OffsetFromAccess(node); |
1374 // Only binary phis are supported for now. | 1325 // Only binary phis are supported for now. |
1375 ProcessLoadFromPhi(offset, from, node, state); | 1326 ProcessLoadFromPhi(offset, from, node, state); |
1376 } else { | 1327 } else { |
1377 UpdateReplacement(state, node, nullptr); | 1328 UpdateReplacement(state, node, nullptr); |
1378 } | 1329 } |
1379 } | 1330 } |
1380 | 1331 |
1381 | |
1382 void EscapeAnalysis::ProcessLoadElement(Node* node) { | 1332 void EscapeAnalysis::ProcessLoadElement(Node* node) { |
1383 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 1333 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); |
1384 ForwardVirtualState(node); | 1334 ForwardVirtualState(node); |
1385 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1335 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1386 VirtualState* state = virtual_states_[node->id()]; | 1336 VirtualState* state = virtual_states_[node->id()]; |
1387 Node* index_node = node->InputAt(1); | 1337 Node* index_node = node->InputAt(1); |
1388 NumberMatcher index(index_node); | 1338 NumberMatcher index(index_node); |
1389 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1339 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
1390 index_node->opcode() != IrOpcode::kInt64Constant && | 1340 index_node->opcode() != IrOpcode::kInt64Constant && |
1391 index_node->opcode() != IrOpcode::kFloat32Constant && | 1341 index_node->opcode() != IrOpcode::kFloat32Constant && |
(...skipping 29 matching lines...) Expand all Loading... |
1421 if (SetEscaped(from)) { | 1371 if (SetEscaped(from)) { |
1422 TRACE( | 1372 TRACE( |
1423 "Setting #%d (%s) to escaped because load element #%d from non-const " | 1373 "Setting #%d (%s) to escaped because load element #%d from non-const " |
1424 "index #%d (%s)\n", | 1374 "index #%d (%s)\n", |
1425 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), | 1375 from->id(), from->op()->mnemonic(), node->id(), index_node->id(), |
1426 index_node->op()->mnemonic()); | 1376 index_node->op()->mnemonic()); |
1427 } | 1377 } |
1428 } | 1378 } |
1429 } | 1379 } |
1430 | 1380 |
1431 | |
1432 void EscapeAnalysis::ProcessStoreField(Node* node) { | 1381 void EscapeAnalysis::ProcessStoreField(Node* node) { |
1433 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 1382 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); |
1434 ForwardVirtualState(node); | 1383 ForwardVirtualState(node); |
1435 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1384 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1436 VirtualState* state = virtual_states_[node->id()]; | 1385 VirtualState* state = virtual_states_[node->id()]; |
1437 VirtualObject* obj = GetVirtualObject(state, to); | 1386 VirtualObject* obj = GetVirtualObject(state, to); |
1438 int offset = OffsetFromAccess(node); | 1387 int offset = OffsetFromAccess(node); |
1439 if (obj && obj->IsTracked() && | 1388 if (obj && obj->IsTracked() && |
1440 static_cast<size_t>(offset) < obj->field_count()) { | 1389 static_cast<size_t>(offset) < obj->field_count()) { |
1441 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); | 1390 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1)); |
1442 if (obj->GetField(offset) != val) { | 1391 if (obj->GetField(offset) != val) { |
1443 obj = CopyForModificationAt(obj, state, node); | 1392 obj = CopyForModificationAt(obj, state, node); |
1444 obj->SetField(offset, val); | 1393 obj->SetField(offset, val); |
1445 } | 1394 } |
1446 } | 1395 } |
1447 } | 1396 } |
1448 | 1397 |
1449 | |
1450 void EscapeAnalysis::ProcessStoreElement(Node* node) { | 1398 void EscapeAnalysis::ProcessStoreElement(Node* node) { |
1451 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 1399 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); |
1452 ForwardVirtualState(node); | 1400 ForwardVirtualState(node); |
1453 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 1401 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); |
1454 Node* index_node = node->InputAt(1); | 1402 Node* index_node = node->InputAt(1); |
1455 NumberMatcher index(index_node); | 1403 NumberMatcher index(index_node); |
1456 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && | 1404 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant && |
1457 index_node->opcode() != IrOpcode::kInt64Constant && | 1405 index_node->opcode() != IrOpcode::kInt64Constant && |
1458 index_node->opcode() != IrOpcode::kFloat32Constant && | 1406 index_node->opcode() != IrOpcode::kFloat32Constant && |
1459 index_node->opcode() != IrOpcode::kFloat64Constant); | 1407 index_node->opcode() != IrOpcode::kFloat64Constant); |
(...skipping 26 matching lines...) Expand all Loading... |
1486 if (!obj->AllFieldsClear()) { | 1434 if (!obj->AllFieldsClear()) { |
1487 obj = CopyForModificationAt(obj, state, node); | 1435 obj = CopyForModificationAt(obj, state, node); |
1488 obj->ClearAllFields(); | 1436 obj->ClearAllFields(); |
1489 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), | 1437 TRACE("Cleared all fields of @%d:#%d\n", GetAlias(obj->id()), |
1490 obj->id()); | 1438 obj->id()); |
1491 } | 1439 } |
1492 } | 1440 } |
1493 } | 1441 } |
1494 } | 1442 } |
1495 | 1443 |
1496 | |
1497 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 1444 Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { |
1498 if ((node->opcode() == IrOpcode::kFinishRegion || | 1445 if ((node->opcode() == IrOpcode::kFinishRegion || |
1499 node->opcode() == IrOpcode::kAllocate) && | 1446 node->opcode() == IrOpcode::kAllocate) && |
1500 IsVirtual(node)) { | 1447 IsVirtual(node)) { |
1501 if (VirtualObject* vobj = | 1448 if (VirtualObject* vobj = |
1502 ResolveVirtualObject(virtual_states_[effect->id()], node)) { | 1449 ResolveVirtualObject(virtual_states_[effect->id()], node)) { |
1503 if (Node* object_state = vobj->GetObjectState()) { | 1450 if (Node* object_state = vobj->GetObjectState()) { |
1504 return object_state; | 1451 return object_state; |
1505 } else { | 1452 } else { |
1506 cache_->fields().clear(); | 1453 cache_->fields().clear(); |
(...skipping 22 matching lines...) Expand all Loading... |
1529 } | 1476 } |
1530 } | 1477 } |
1531 } | 1478 } |
1532 return new_object_state; | 1479 return new_object_state; |
1533 } | 1480 } |
1534 } | 1481 } |
1535 } | 1482 } |
1536 return nullptr; | 1483 return nullptr; |
1537 } | 1484 } |
1538 | 1485 |
1539 | |
1540 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) { | 1486 void EscapeAnalysis::DebugPrintObject(VirtualObject* object, Alias alias) { |
1541 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(), | 1487 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(), |
1542 object->field_count()); | 1488 object->field_count()); |
1543 for (size_t i = 0; i < object->field_count(); ++i) { | 1489 for (size_t i = 0; i < object->field_count(); ++i) { |
1544 if (Node* f = object->GetField(i)) { | 1490 if (Node* f = object->GetField(i)) { |
1545 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); | 1491 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic()); |
1546 } | 1492 } |
1547 } | 1493 } |
1548 } | 1494 } |
1549 | 1495 |
1550 | |
1551 void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 1496 void EscapeAnalysis::DebugPrintState(VirtualState* state) { |
1552 PrintF("Dumping virtual state %p\n", static_cast<void*>(state)); | 1497 PrintF("Dumping virtual state %p\n", static_cast<void*>(state)); |
1553 for (Alias alias = 0; alias < AliasCount(); ++alias) { | 1498 for (Alias alias = 0; alias < AliasCount(); ++alias) { |
1554 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { | 1499 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { |
1555 DebugPrintObject(object, alias); | 1500 DebugPrintObject(object, alias); |
1556 } | 1501 } |
1557 } | 1502 } |
1558 } | 1503 } |
1559 | 1504 |
1560 | |
1561 void EscapeAnalysis::DebugPrint() { | 1505 void EscapeAnalysis::DebugPrint() { |
1562 ZoneVector<VirtualState*> object_states(zone()); | 1506 ZoneVector<VirtualState*> object_states(zone()); |
1563 for (NodeId id = 0; id < virtual_states_.size(); id++) { | 1507 for (NodeId id = 0; id < virtual_states_.size(); id++) { |
1564 if (VirtualState* states = virtual_states_[id]) { | 1508 if (VirtualState* states = virtual_states_[id]) { |
1565 if (std::find(object_states.begin(), object_states.end(), states) == | 1509 if (std::find(object_states.begin(), object_states.end(), states) == |
1566 object_states.end()) { | 1510 object_states.end()) { |
1567 object_states.push_back(states); | 1511 object_states.push_back(states); |
1568 } | 1512 } |
1569 } | 1513 } |
1570 } | 1514 } |
1571 for (size_t n = 0; n < object_states.size(); n++) { | 1515 for (size_t n = 0; n < object_states.size(); n++) { |
1572 DebugPrintState(object_states[n]); | 1516 DebugPrintState(object_states[n]); |
1573 } | 1517 } |
1574 } | 1518 } |
1575 | 1519 |
1576 | |
1577 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, | 1520 VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, |
1578 Node* node) { | 1521 Node* node) { |
1579 if (node->id() >= status_analysis_.GetAliasMap().size()) return nullptr; | 1522 if (node->id() >= status_analysis_.GetAliasMap().size()) return nullptr; |
1580 Alias alias = GetAlias(node->id()); | 1523 Alias alias = GetAlias(node->id()); |
1581 if (alias >= state->size()) return nullptr; | 1524 if (alias >= state->size()) return nullptr; |
1582 return state->VirtualObjectFromAlias(alias); | 1525 return state->VirtualObjectFromAlias(alias); |
1583 } | 1526 } |
1584 | 1527 |
1585 | |
1586 bool EscapeAnalysis::ExistsVirtualAllocate() { | 1528 bool EscapeAnalysis::ExistsVirtualAllocate() { |
1587 for (size_t id = 0; id < status_analysis_.GetAliasMap().size(); ++id) { | 1529 for (size_t id = 0; id < status_analysis_.GetAliasMap().size(); ++id) { |
1588 Alias alias = GetAlias(static_cast<NodeId>(id)); | 1530 Alias alias = GetAlias(static_cast<NodeId>(id)); |
1589 if (alias < EscapeStatusAnalysis::kUntrackable) { | 1531 if (alias < EscapeStatusAnalysis::kUntrackable) { |
1590 if (status_analysis_.IsVirtual(static_cast<int>(id))) { | 1532 if (status_analysis_.IsVirtual(static_cast<int>(id))) { |
1591 return true; | 1533 return true; |
1592 } | 1534 } |
1593 } | 1535 } |
1594 } | 1536 } |
1595 return false; | 1537 return false; |
1596 } | 1538 } |
1597 | 1539 |
1598 } // namespace compiler | 1540 } // namespace compiler |
1599 } // namespace internal | 1541 } // namespace internal |
1600 } // namespace v8 | 1542 } // namespace v8 |
OLD | NEW |