Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: src/compiler/escape-analysis.cc

Issue 1606613002: [turbofan] Memory improvements for escape analysis (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@stage-fix
Patch Set: Unstage for landing Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/escape-analysis.h ('k') | src/compiler/escape-analysis-reducer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698