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