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