| 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 |