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

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: Rebase Created 4 years, 11 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
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> 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
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698