blob: d11c3ab674dd22ea26b8b109729d0e2280113e50 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
3// found in the LICENSE file.
4
5#include "src/compiler/escape-analysis.h"
6
7#include <limits>
8
9#include "src/base/flags.h"
10#include "src/bootstrapper.h"
11#include "src/compilation-dependencies.h"
12#include "src/compiler/common-operator.h"
13#include "src/compiler/graph-reducer.h"
14#include "src/compiler/js-operator.h"
15#include "src/compiler/node.h"
16#include "src/compiler/node-matchers.h"
17#include "src/compiler/node-properties.h"
18#include "src/compiler/operator-properties.h"
19#include "src/compiler/simplified-operator.h"
20#include "src/objects-inl.h"
21#include "src/type-cache.h"
22
23namespace v8 {
24namespace internal {
25namespace compiler {
26
Ben Murdochc5610432016-08-08 18:44:38 +010027typedef NodeId Alias;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028
Ben Murdoch097c5b22016-05-18 11:27:45 +010029#ifdef DEBUG
30#define TRACE(...) \
31 do { \
32 if (FLAG_trace_turbo_escape) PrintF(__VA_ARGS__); \
33 } while (false)
34#else
35#define TRACE(...)
36#endif
37
Ben Murdochc5610432016-08-08 18:44:38 +010038// EscapeStatusAnalysis determines for each allocation whether it escapes.
39class EscapeStatusAnalysis : public ZoneObject {
40 public:
41 enum Status {
42 kUnknown = 0u,
43 kTracked = 1u << 0,
44 kEscaped = 1u << 1,
45 kOnStack = 1u << 2,
46 kVisited = 1u << 3,
47 // A node is dangling, if it is a load of some kind, and does not have
48 // an effect successor.
49 kDanglingComputed = 1u << 4,
50 kDangling = 1u << 5,
51 // A node is is an effect branch point, if it has more than 2 non-dangling
52 // effect successors.
53 kBranchPointComputed = 1u << 6,
54 kBranchPoint = 1u << 7,
55 kInQueue = 1u << 8
56 };
57 typedef base::Flags<Status, uint16_t> StatusFlags;
58
59 void RunStatusAnalysis();
60
61 bool IsVirtual(Node* node);
62 bool IsEscaped(Node* node);
63 bool IsAllocation(Node* node);
64
65 bool IsInQueue(NodeId id);
66 void SetInQueue(NodeId id, bool on_stack);
67
68 void DebugPrint();
69
70 EscapeStatusAnalysis(EscapeAnalysis* object_analysis, Graph* graph,
71 Zone* zone);
72 void EnqueueForStatusAnalysis(Node* node);
73 bool SetEscaped(Node* node);
74 bool IsEffectBranchPoint(Node* node);
75 bool IsDanglingEffectNode(Node* node);
76 void ResizeStatusVector();
77 size_t GetStatusVectorSize();
78 bool IsVirtual(NodeId id);
79
80 Graph* graph() const { return graph_; }
81 void AssignAliases();
82 Alias GetAlias(NodeId id) const { return aliases_[id]; }
83 const ZoneVector<Alias>& GetAliasMap() const { return aliases_; }
84 Alias AliasCount() const { return next_free_alias_; }
85 static const Alias kNotReachable;
86 static const Alias kUntrackable;
87
88 bool IsNotReachable(Node* node);
89
90 private:
91 void Process(Node* node);
92 void ProcessAllocate(Node* node);
93 void ProcessFinishRegion(Node* node);
94 void ProcessStoreField(Node* node);
95 void ProcessStoreElement(Node* node);
96 bool CheckUsesForEscape(Node* node, bool phi_escaping = false) {
97 return CheckUsesForEscape(node, node, phi_escaping);
98 }
99 bool CheckUsesForEscape(Node* node, Node* rep, bool phi_escaping = false);
100 void RevisitUses(Node* node);
101 void RevisitInputs(Node* node);
102
103 Alias NextAlias() { return next_free_alias_++; }
104
105 bool HasEntry(Node* node);
106
107 bool IsAllocationPhi(Node* node);
108
109 ZoneVector<Node*> stack_;
110 EscapeAnalysis* object_analysis_;
111 Graph* const graph_;
112 ZoneVector<StatusFlags> status_;
113 Alias next_free_alias_;
114 ZoneVector<Node*> status_stack_;
115 ZoneVector<Alias> aliases_;
116
117 DISALLOW_COPY_AND_ASSIGN(EscapeStatusAnalysis);
118};
119
120DEFINE_OPERATORS_FOR_FLAGS(EscapeStatusAnalysis::StatusFlags)
121
Ben Murdoch097c5b22016-05-18 11:27:45 +0100122const Alias EscapeStatusAnalysis::kNotReachable =
123 std::numeric_limits<Alias>::max();
124const Alias EscapeStatusAnalysis::kUntrackable =
125 std::numeric_limits<Alias>::max() - 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126
127class VirtualObject : public ZoneObject {
128 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100129 enum Status {
130 kInitial = 0,
131 kTracked = 1u << 0,
132 kInitialized = 1u << 1,
133 kCopyRequired = 1u << 2,
134 };
135 typedef base::Flags<Status, unsigned char> StatusFlags;
136
137 VirtualObject(NodeId id, VirtualState* owner, Zone* zone)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 : id_(id),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100139 status_(kInitial),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 fields_(zone),
141 phi_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100142 object_state_(nullptr),
143 owner_(owner) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000144
Ben Murdoch097c5b22016-05-18 11:27:45 +0100145 VirtualObject(VirtualState* owner, const VirtualObject& other)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 : id_(other.id_),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100147 status_(other.status_ & ~kCopyRequired),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 fields_(other.fields_),
149 phi_(other.phi_),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100150 object_state_(other.object_state_),
151 owner_(owner) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152
Ben Murdoch097c5b22016-05-18 11:27:45 +0100153 VirtualObject(NodeId id, VirtualState* owner, Zone* zone, size_t field_number,
154 bool initialized)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000155 : id_(id),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100156 status_(kTracked | (initialized ? kInitialized : kInitial)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 fields_(zone),
158 phi_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100159 object_state_(nullptr),
160 owner_(owner) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 fields_.resize(field_number);
162 phi_.resize(field_number, false);
163 }
164
Ben Murdoch097c5b22016-05-18 11:27:45 +0100165 Node* GetField(size_t offset) { return fields_[offset]; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166
Ben Murdoch097c5b22016-05-18 11:27:45 +0100167 bool IsCreatedPhi(size_t offset) { return phi_[offset]; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000168
Ben Murdoch097c5b22016-05-18 11:27:45 +0100169 void SetField(size_t offset, Node* node, bool created_phi = false) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170 fields_[offset] = node;
171 phi_[offset] = created_phi;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100173 bool IsTracked() const { return status_ & kTracked; }
174 bool IsInitialized() const { return status_ & kInitialized; }
175 bool SetInitialized() { return status_ |= kInitialized; }
176 VirtualState* owner() const { return owner_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177
178 Node** fields_array() { return &fields_.front(); }
179 size_t field_count() { return fields_.size(); }
180 bool ResizeFields(size_t field_count) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100181 if (field_count > fields_.size()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 fields_.resize(field_count);
183 phi_.resize(field_count);
184 return true;
185 }
186 return false;
187 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100188 void ClearAllFields() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000189 for (size_t i = 0; i < fields_.size(); ++i) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100190 fields_[i] = nullptr;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000191 phi_[i] = false;
192 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100193 }
194 bool AllFieldsClear() {
195 for (size_t i = 0; i < fields_.size(); ++i) {
196 if (fields_[i] != nullptr) {
197 return false;
198 }
199 }
200 return true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000201 }
202 bool UpdateFrom(const VirtualObject& other);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100203 bool MergeFrom(MergeCache* cache, Node* at, Graph* graph,
204 CommonOperatorBuilder* common);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 void SetObjectState(Node* node) { object_state_ = node; }
206 Node* GetObjectState() const { return object_state_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100207 bool IsCopyRequired() const { return status_ & kCopyRequired; }
208 void SetCopyRequired() { status_ |= kCopyRequired; }
209 bool NeedCopyForModification() {
210 if (!IsCopyRequired() || !IsInitialized()) {
211 return false;
212 }
213 return true;
214 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215
216 NodeId id() const { return id_; }
217 void id(NodeId id) { id_ = id; }
218
219 private:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 bool MergeFields(size_t i, Node* at, MergeCache* cache, Graph* graph,
221 CommonOperatorBuilder* common);
222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 NodeId id_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100224 StatusFlags status_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 ZoneVector<Node*> fields_;
226 ZoneVector<bool> phi_;
227 Node* object_state_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 VirtualState* owner_;
229
230 DISALLOW_COPY_AND_ASSIGN(VirtualObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231};
232
Ben Murdoch097c5b22016-05-18 11:27:45 +0100233DEFINE_OPERATORS_FOR_FLAGS(VirtualObject::StatusFlags)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000234
235bool VirtualObject::UpdateFrom(const VirtualObject& other) {
236 bool changed = status_ != other.status_;
237 status_ = other.status_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 phi_ = other.phi_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 if (fields_.size() != other.fields_.size()) {
240 fields_ = other.fields_;
241 return true;
242 }
243 for (size_t i = 0; i < fields_.size(); ++i) {
244 if (fields_[i] != other.fields_[i]) {
245 changed = true;
246 fields_[i] = other.fields_[i];
247 }
248 }
249 return changed;
250}
251
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252class VirtualState : public ZoneObject {
253 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100254 VirtualState(Node* owner, Zone* zone, size_t size)
255 : info_(size, nullptr, zone), owner_(owner) {}
256
257 VirtualState(Node* owner, const VirtualState& state)
258 : info_(state.info_.size(), nullptr, state.info_.get_allocator().zone()),
259 owner_(owner) {
260 for (size_t i = 0; i < info_.size(); ++i) {
261 if (state.info_[i]) {
262 info_[i] = state.info_[i];
263 }
264 }
265 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000266
267 VirtualObject* VirtualObjectFromAlias(size_t alias);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100268 void SetVirtualObject(Alias alias, VirtualObject* state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000269 bool UpdateFrom(VirtualState* state, Zone* zone);
270 bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 CommonOperatorBuilder* common, Node* at);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272 size_t size() const { return info_.size(); }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100273 Node* owner() const { return owner_; }
274 VirtualObject* Copy(VirtualObject* obj, Alias alias);
275 void SetCopyRequired() {
276 for (VirtualObject* obj : info_) {
277 if (obj) obj->SetCopyRequired();
278 }
279 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280
281 private:
282 ZoneVector<VirtualObject*> info_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100283 Node* owner_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000284
Ben Murdoch097c5b22016-05-18 11:27:45 +0100285 DISALLOW_COPY_AND_ASSIGN(VirtualState);
286};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287
288class MergeCache : public ZoneObject {
289 public:
290 explicit MergeCache(Zone* zone)
291 : states_(zone), objects_(zone), fields_(zone) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100292 states_.reserve(5);
293 objects_.reserve(5);
294 fields_.reserve(5);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 }
296 ZoneVector<VirtualState*>& states() { return states_; }
297 ZoneVector<VirtualObject*>& objects() { return objects_; }
298 ZoneVector<Node*>& fields() { return fields_; }
299 void Clear() {
300 states_.clear();
301 objects_.clear();
302 fields_.clear();
303 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 size_t LoadVirtualObjectsFromStatesFor(Alias alias);
305 void LoadVirtualObjectsForFieldsFrom(VirtualState* state,
306 const ZoneVector<Alias>& aliases);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000307 Node* GetFields(size_t pos);
308
309 private:
310 ZoneVector<VirtualState*> states_;
311 ZoneVector<VirtualObject*> objects_;
312 ZoneVector<Node*> fields_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100313
314 DISALLOW_COPY_AND_ASSIGN(MergeCache);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315};
316
Ben Murdoch097c5b22016-05-18 11:27:45 +0100317size_t MergeCache::LoadVirtualObjectsFromStatesFor(Alias alias) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 objects_.clear();
319 DCHECK_GT(states_.size(), 0u);
320 size_t min = std::numeric_limits<size_t>::max();
321 for (VirtualState* state : states_) {
322 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
323 objects_.push_back(obj);
324 min = std::min(obj->field_count(), min);
325 }
326 }
327 return min;
328}
329
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000330void MergeCache::LoadVirtualObjectsForFieldsFrom(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100331 VirtualState* state, const ZoneVector<Alias>& aliases) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 objects_.clear();
333 size_t max_alias = state->size();
334 for (Node* field : fields_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100335 Alias alias = aliases[field->id()];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 if (alias >= max_alias) continue;
337 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
338 objects_.push_back(obj);
339 }
340 }
341}
342
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343Node* MergeCache::GetFields(size_t pos) {
344 fields_.clear();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100345 Node* rep = pos >= objects_.front()->field_count()
346 ? nullptr
347 : objects_.front()->GetField(pos);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 for (VirtualObject* obj : objects_) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100349 if (pos >= obj->field_count()) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350 Node* field = obj->GetField(pos);
351 if (field) {
352 fields_.push_back(field);
353 }
354 if (field != rep) {
355 rep = nullptr;
356 }
357 }
358 return rep;
359}
360
Ben Murdoch097c5b22016-05-18 11:27:45 +0100361VirtualObject* VirtualState::Copy(VirtualObject* obj, Alias alias) {
362 if (obj->owner() == this) return obj;
363 VirtualObject* new_obj =
364 new (info_.get_allocator().zone()) VirtualObject(this, *obj);
365 TRACE("At state %p, alias @%d (#%d), copying virtual object from %p to %p\n",
366 static_cast<void*>(this), alias, obj->id(), static_cast<void*>(obj),
367 static_cast<void*>(new_obj));
368 info_[alias] = new_obj;
369 return new_obj;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370}
371
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) {
373 return info_[alias];
374}
375
Ben Murdoch097c5b22016-05-18 11:27:45 +0100376void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000377 info_[alias] = obj;
378}
379
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100381 if (from == this) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 bool changed = false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100383 for (Alias alias = 0; alias < size(); ++alias) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 VirtualObject* ls = VirtualObjectFromAlias(alias);
385 VirtualObject* rs = from->VirtualObjectFromAlias(alias);
386
Ben Murdoch097c5b22016-05-18 11:27:45 +0100387 if (ls == rs || rs == nullptr) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000388
389 if (ls == nullptr) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100390 ls = new (zone) VirtualObject(this, *rs);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000391 SetVirtualObject(alias, ls);
392 changed = true;
393 continue;
394 }
395
Ben Murdoch097c5b22016-05-18 11:27:45 +0100396 TRACE(" Updating fields of @%d\n", alias);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397
398 changed = ls->UpdateFrom(*rs) || changed;
399 }
400 return false;
401}
402
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000403namespace {
404
405bool IsEquivalentPhi(Node* node1, Node* node2) {
406 if (node1 == node2) return true;
407 if (node1->opcode() != IrOpcode::kPhi || node2->opcode() != IrOpcode::kPhi ||
408 node1->op()->ValueInputCount() != node2->op()->ValueInputCount()) {
409 return false;
410 }
411 for (int i = 0; i < node1->op()->ValueInputCount(); ++i) {
412 Node* input1 = NodeProperties::GetValueInput(node1, i);
413 Node* input2 = NodeProperties::GetValueInput(node2, i);
414 if (!IsEquivalentPhi(input1, input2)) {
415 return false;
416 }
417 }
418 return true;
419}
420
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000421bool IsEquivalentPhi(Node* phi, ZoneVector<Node*>& inputs) {
422 if (phi->opcode() != IrOpcode::kPhi) return false;
423 if (phi->op()->ValueInputCount() != inputs.size()) {
424 return false;
425 }
426 for (size_t i = 0; i < inputs.size(); ++i) {
427 Node* input = NodeProperties::GetValueInput(phi, static_cast<int>(i));
428 if (!IsEquivalentPhi(input, inputs[i])) {
429 return false;
430 }
431 }
432 return true;
433}
434
435} // namespace
436
Ben Murdoch097c5b22016-05-18 11:27:45 +0100437bool VirtualObject::MergeFields(size_t i, Node* at, MergeCache* cache,
438 Graph* graph, CommonOperatorBuilder* common) {
439 bool changed = false;
440 int value_input_count = static_cast<int>(cache->fields().size());
441 Node* rep = GetField(i);
442 if (!rep || !IsCreatedPhi(i)) {
443 Node* control = NodeProperties::GetControlInput(at);
444 cache->fields().push_back(control);
445 Node* phi = graph->NewNode(
446 common->Phi(MachineRepresentation::kTagged, value_input_count),
447 value_input_count + 1, &cache->fields().front());
448 SetField(i, phi, true);
449#ifdef DEBUG
450 if (FLAG_trace_turbo_escape) {
451 PrintF(" Creating Phi #%d as merge of", phi->id());
452 for (int i = 0; i < value_input_count; i++) {
453 PrintF(" #%d (%s)", cache->fields()[i]->id(),
454 cache->fields()[i]->op()->mnemonic());
455 }
456 PrintF("\n");
457 }
458#endif
459 changed = true;
460 } else {
461 DCHECK(rep->opcode() == IrOpcode::kPhi);
462 for (int n = 0; n < value_input_count; ++n) {
463 Node* old = NodeProperties::GetValueInput(rep, n);
464 if (old != cache->fields()[n]) {
465 changed = true;
466 NodeProperties::ReplaceValueInput(rep, cache->fields()[n], n);
467 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000468 }
469 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100470 return changed;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000471}
472
Ben Murdoch097c5b22016-05-18 11:27:45 +0100473bool VirtualObject::MergeFrom(MergeCache* cache, Node* at, Graph* graph,
474 CommonOperatorBuilder* common) {
475 DCHECK(at->opcode() == IrOpcode::kEffectPhi ||
476 at->opcode() == IrOpcode::kPhi);
477 bool changed = false;
478 for (size_t i = 0; i < field_count(); ++i) {
479 if (Node* field = cache->GetFields(i)) {
480 changed = changed || GetField(i) != field;
481 SetField(i, field);
482 TRACE(" Field %zu agree on rep #%d\n", i, field->id());
483 } else {
484 int arity = at->opcode() == IrOpcode::kEffectPhi
485 ? at->op()->EffectInputCount()
486 : at->op()->ValueInputCount();
487 if (cache->fields().size() == arity) {
488 changed = MergeFields(i, at, cache, graph, common) || changed;
489 } else {
490 if (GetField(i) != nullptr) {
491 TRACE(" Field %zu cleared\n", i);
492 changed = true;
493 }
494 SetField(i, nullptr);
495 }
496 }
497 }
498 return changed;
499}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000500
501bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100502 CommonOperatorBuilder* common, Node* at) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000503 DCHECK_GT(cache->states().size(), 0u);
504 bool changed = false;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100505 for (Alias alias = 0; alias < size(); ++alias) {
506 cache->objects().clear();
507 VirtualObject* mergeObject = VirtualObjectFromAlias(alias);
508 bool copy_merge_object = false;
509 size_t fields = std::numeric_limits<size_t>::max();
510 for (VirtualState* state : cache->states()) {
511 if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) {
512 cache->objects().push_back(obj);
513 if (mergeObject == obj) {
514 copy_merge_object = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000515 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100516 fields = std::min(obj->field_count(), fields);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100518 }
519 if (cache->objects().size() == cache->states().size()) {
520 if (!mergeObject) {
521 VirtualObject* obj = new (zone)
522 VirtualObject(cache->objects().front()->id(), this, zone, fields,
523 cache->objects().front()->IsInitialized());
524 SetVirtualObject(alias, obj);
525 mergeObject = obj;
526 changed = true;
527 } else if (copy_merge_object) {
528 VirtualObject* obj = new (zone) VirtualObject(this, *mergeObject);
529 SetVirtualObject(alias, obj);
530 mergeObject = obj;
531 changed = true;
532 } else {
533 changed = mergeObject->ResizeFields(fields) || changed;
534 }
535#ifdef DEBUG
536 if (FLAG_trace_turbo_escape) {
537 PrintF(" Alias @%d, merging into %p virtual objects", alias,
538 static_cast<void*>(mergeObject));
539 for (size_t i = 0; i < cache->objects().size(); i++) {
540 PrintF(" %p", static_cast<void*>(cache->objects()[i]));
541 }
542 PrintF("\n");
543 }
544#endif // DEBUG
545 changed = mergeObject->MergeFrom(cache, at, graph, common) || changed;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000546 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100547 if (mergeObject) {
548 TRACE(" Alias %d, virtual object removed\n", alias);
549 changed = true;
550 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 SetVirtualObject(alias, nullptr);
552 }
553 }
554 return changed;
555}
556
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis,
558 Graph* graph, Zone* zone)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100559 : stack_(zone),
560 object_analysis_(object_analysis),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000561 graph_(graph),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100562 status_(zone),
563 next_free_alias_(0),
564 status_stack_(zone),
565 aliases_(zone) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000567bool EscapeStatusAnalysis::HasEntry(Node* node) {
568 return status_[node->id()] & (kTracked | kEscaped);
569}
570
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000571bool EscapeStatusAnalysis::IsVirtual(Node* node) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100572 return IsVirtual(node->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573}
574
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575bool EscapeStatusAnalysis::IsVirtual(NodeId id) {
576 return (status_[id] & kTracked) && !(status_[id] & kEscaped);
577}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000578
579bool EscapeStatusAnalysis::IsEscaped(Node* node) {
580 return status_[node->id()] & kEscaped;
581}
582
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000583bool EscapeStatusAnalysis::IsAllocation(Node* node) {
584 return node->opcode() == IrOpcode::kAllocate ||
585 node->opcode() == IrOpcode::kFinishRegion;
586}
587
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000588bool EscapeStatusAnalysis::SetEscaped(Node* node) {
589 bool changed = !(status_[node->id()] & kEscaped);
590 status_[node->id()] |= kEscaped | kTracked;
591 return changed;
592}
593
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594bool EscapeStatusAnalysis::IsInQueue(NodeId id) {
595 return status_[id] & kInQueue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000596}
597
Ben Murdoch097c5b22016-05-18 11:27:45 +0100598void EscapeStatusAnalysis::SetInQueue(NodeId id, bool on_stack) {
599 if (on_stack) {
600 status_[id] |= kInQueue;
601 } else {
602 status_[id] &= ~kInQueue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000603 }
604}
605
Ben Murdoch097c5b22016-05-18 11:27:45 +0100606void EscapeStatusAnalysis::ResizeStatusVector() {
607 if (status_.size() <= graph()->NodeCount()) {
608 status_.resize(graph()->NodeCount() * 1.1, kUnknown);
609 }
610}
611
612size_t EscapeStatusAnalysis::GetStatusVectorSize() { return status_.size(); }
613
614void EscapeStatusAnalysis::RunStatusAnalysis() {
615 ResizeStatusVector();
616 while (!status_stack_.empty()) {
617 Node* node = status_stack_.back();
618 status_stack_.pop_back();
619 status_[node->id()] &= ~kOnStack;
620 Process(node);
621 status_[node->id()] |= kVisited;
622 }
623}
624
625void EscapeStatusAnalysis::EnqueueForStatusAnalysis(Node* node) {
626 DCHECK_NOT_NULL(node);
627 if (!(status_[node->id()] & kOnStack)) {
628 status_stack_.push_back(node);
629 status_[node->id()] |= kOnStack;
630 }
631}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632
633void EscapeStatusAnalysis::RevisitInputs(Node* node) {
634 for (Edge edge : node->input_edges()) {
635 Node* input = edge.to();
636 if (!(status_[input->id()] & kOnStack)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100637 status_stack_.push_back(input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000638 status_[input->id()] |= kOnStack;
639 }
640 }
641}
642
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000643void EscapeStatusAnalysis::RevisitUses(Node* node) {
644 for (Edge edge : node->use_edges()) {
645 Node* use = edge.from();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100646 if (!(status_[use->id()] & kOnStack) && !IsNotReachable(use)) {
647 status_stack_.push_back(use);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000648 status_[use->id()] |= kOnStack;
649 }
650 }
651}
652
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000653void EscapeStatusAnalysis::Process(Node* node) {
654 switch (node->opcode()) {
655 case IrOpcode::kAllocate:
656 ProcessAllocate(node);
657 break;
658 case IrOpcode::kFinishRegion:
659 ProcessFinishRegion(node);
660 break;
661 case IrOpcode::kStoreField:
662 ProcessStoreField(node);
663 break;
664 case IrOpcode::kStoreElement:
665 ProcessStoreElement(node);
666 break;
667 case IrOpcode::kLoadField:
668 case IrOpcode::kLoadElement: {
669 if (Node* rep = object_analysis_->GetReplacement(node)) {
670 if (IsAllocation(rep) && CheckUsesForEscape(node, rep)) {
671 RevisitInputs(rep);
672 RevisitUses(rep);
673 }
674 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100675 RevisitUses(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000676 break;
677 }
678 case IrOpcode::kPhi:
679 if (!HasEntry(node)) {
680 status_[node->id()] |= kTracked;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100681 RevisitUses(node);
682 }
683 if (!IsAllocationPhi(node) && SetEscaped(node)) {
684 RevisitInputs(node);
685 RevisitUses(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 }
687 CheckUsesForEscape(node);
688 default:
689 break;
690 }
691}
692
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000693bool EscapeStatusAnalysis::IsAllocationPhi(Node* node) {
694 for (Edge edge : node->input_edges()) {
695 Node* input = edge.to();
696 if (input->opcode() == IrOpcode::kPhi && !IsEscaped(input)) continue;
697 if (IsAllocation(input)) continue;
698 return false;
699 }
700 return true;
701}
702
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703void EscapeStatusAnalysis::ProcessStoreField(Node* node) {
704 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
705 Node* to = NodeProperties::GetValueInput(node, 0);
706 Node* val = NodeProperties::GetValueInput(node, 1);
707 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) {
708 RevisitUses(val);
709 RevisitInputs(val);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100710 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n",
711 val->id(), val->op()->mnemonic(), to->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000712 }
713}
714
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715void EscapeStatusAnalysis::ProcessStoreElement(Node* node) {
716 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
717 Node* to = NodeProperties::GetValueInput(node, 0);
718 Node* val = NodeProperties::GetValueInput(node, 2);
719 if ((IsEscaped(to) || !IsAllocation(to)) && SetEscaped(val)) {
720 RevisitUses(val);
721 RevisitInputs(val);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100722 TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n",
723 val->id(), val->op()->mnemonic(), to->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 }
725}
726
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000727void EscapeStatusAnalysis::ProcessAllocate(Node* node) {
728 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
729 if (!HasEntry(node)) {
730 status_[node->id()] |= kTracked;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100731 TRACE("Created status entry for node #%d (%s)\n", node->id(),
732 node->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000733 NumberMatcher size(node->InputAt(0));
734 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant &&
735 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant &&
736 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant &&
737 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100738 RevisitUses(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000739 if (!size.HasValue() && SetEscaped(node)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100740 TRACE("Setting #%d to escaped because of non-const alloc\n", node->id());
741 // This node is already known to escape, uses do not have to be checked
742 // for escape.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000743 return;
744 }
745 }
746 if (CheckUsesForEscape(node, true)) {
747 RevisitUses(node);
748 }
749}
750
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000751bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep,
752 bool phi_escaping) {
753 for (Edge edge : uses->use_edges()) {
754 Node* use = edge.from();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100755 if (IsNotReachable(use)) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756 if (edge.index() >= use->op()->ValueInputCount() +
757 OperatorProperties::GetContextInputCount(use->op()))
758 continue;
759 switch (use->opcode()) {
760 case IrOpcode::kPhi:
761 if (phi_escaping && SetEscaped(rep)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100762 TRACE(
763 "Setting #%d (%s) to escaped because of use by phi node "
764 "#%d (%s)\n",
765 rep->id(), rep->op()->mnemonic(), use->id(),
766 use->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000767 return true;
768 }
769 // Fallthrough.
770 case IrOpcode::kStoreField:
771 case IrOpcode::kLoadField:
772 case IrOpcode::kStoreElement:
773 case IrOpcode::kLoadElement:
774 case IrOpcode::kFrameState:
775 case IrOpcode::kStateValues:
776 case IrOpcode::kReferenceEqual:
777 case IrOpcode::kFinishRegion:
778 if (IsEscaped(use) && SetEscaped(rep)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100779 TRACE(
780 "Setting #%d (%s) to escaped because of use by escaping node "
781 "#%d (%s)\n",
782 rep->id(), rep->op()->mnemonic(), use->id(),
783 use->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000784 return true;
785 }
786 break;
787 case IrOpcode::kObjectIsSmi:
788 if (!IsAllocation(rep) && SetEscaped(rep)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100789 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
790 rep->id(), rep->op()->mnemonic(), use->id(),
791 use->op()->mnemonic());
792 return true;
793 }
794 break;
795 case IrOpcode::kSelect:
Ben Murdochc5610432016-08-08 18:44:38 +0100796 case IrOpcode::kTypeGuard:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100797 if (SetEscaped(rep)) {
798 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
799 rep->id(), rep->op()->mnemonic(), use->id(),
800 use->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000801 return true;
802 }
803 break;
804 default:
805 if (use->op()->EffectInputCount() == 0 &&
Ben Murdochc5610432016-08-08 18:44:38 +0100806 uses->op()->EffectInputCount() > 0 &&
807 !IrOpcode::IsJsOpcode(use->opcode())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100808 TRACE("Encountered unaccounted use by #%d (%s)\n", use->id(),
809 use->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000810 UNREACHABLE();
811 }
812 if (SetEscaped(rep)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100813 TRACE("Setting #%d (%s) to escaped because of use by #%d (%s)\n",
814 rep->id(), rep->op()->mnemonic(), use->id(),
815 use->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000816 return true;
817 }
818 }
819 }
820 return false;
821}
822
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000823void EscapeStatusAnalysis::ProcessFinishRegion(Node* node) {
824 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
825 if (!HasEntry(node)) {
826 status_[node->id()] |= kTracked;
827 RevisitUses(node);
828 }
829 if (CheckUsesForEscape(node, true)) {
830 RevisitInputs(node);
831 }
832}
833
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000834void EscapeStatusAnalysis::DebugPrint() {
835 for (NodeId id = 0; id < status_.size(); id++) {
836 if (status_[id] & kTracked) {
837 PrintF("Node #%d is %s\n", id,
838 (status_[id] & kEscaped) ? "escaping" : "virtual");
839 }
840 }
841}
842
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000843EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common,
844 Zone* zone)
Ben Murdochc5610432016-08-08 18:44:38 +0100845 : zone_(zone),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000846 common_(common),
Ben Murdochc5610432016-08-08 18:44:38 +0100847 status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000848 virtual_states_(zone),
849 replacements_(zone),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100850 cache_(nullptr) {}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000851
852EscapeAnalysis::~EscapeAnalysis() {}
853
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000854void EscapeAnalysis::Run() {
855 replacements_.resize(graph()->NodeCount());
Ben Murdochc5610432016-08-08 18:44:38 +0100856 status_analysis_->AssignAliases();
857 if (status_analysis_->AliasCount() > 0) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100858 cache_ = new (zone()) MergeCache(zone());
859 replacements_.resize(graph()->NodeCount());
Ben Murdochc5610432016-08-08 18:44:38 +0100860 status_analysis_->ResizeStatusVector();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100861 RunObjectAnalysis();
Ben Murdochc5610432016-08-08 18:44:38 +0100862 status_analysis_->RunStatusAnalysis();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100863 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000864}
865
Ben Murdoch097c5b22016-05-18 11:27:45 +0100866void EscapeStatusAnalysis::AssignAliases() {
867 size_t max_size = 1024;
868 size_t min_size = 32;
869 size_t stack_size =
870 std::min(std::max(graph()->NodeCount() / 5, min_size), max_size);
871 stack_.reserve(stack_size);
872 ResizeStatusVector();
873 stack_.push_back(graph()->end());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000874 CHECK_LT(graph()->NodeCount(), kUntrackable);
875 aliases_.resize(graph()->NodeCount(), kNotReachable);
876 aliases_[graph()->end()->id()] = kUntrackable;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100877 status_stack_.reserve(8);
878 TRACE("Discovering trackable nodes");
879 while (!stack_.empty()) {
880 Node* node = stack_.back();
881 stack_.pop_back();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000882 switch (node->opcode()) {
883 case IrOpcode::kAllocate:
884 if (aliases_[node->id()] >= kUntrackable) {
885 aliases_[node->id()] = NextAlias();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100886 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(),
887 node->id());
888 EnqueueForStatusAnalysis(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000889 }
890 break;
891 case IrOpcode::kFinishRegion: {
892 Node* allocate = NodeProperties::GetValueInput(node, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100893 DCHECK_NOT_NULL(allocate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 if (allocate->opcode() == IrOpcode::kAllocate) {
895 if (aliases_[allocate->id()] >= kUntrackable) {
896 if (aliases_[allocate->id()] == kNotReachable) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100897 stack_.push_back(allocate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000898 }
899 aliases_[allocate->id()] = NextAlias();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100900 TRACE(" @%d:%s#%u", aliases_[allocate->id()],
901 allocate->op()->mnemonic(), allocate->id());
902 EnqueueForStatusAnalysis(allocate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 }
904 aliases_[node->id()] = aliases_[allocate->id()];
Ben Murdoch097c5b22016-05-18 11:27:45 +0100905 TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(),
906 node->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000907 }
908 break;
909 }
910 default:
911 DCHECK_EQ(aliases_[node->id()], kUntrackable);
912 break;
913 }
914 for (Edge edge : node->input_edges()) {
915 Node* input = edge.to();
916 if (aliases_[input->id()] == kNotReachable) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100917 stack_.push_back(input);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000918 aliases_[input->id()] = kUntrackable;
919 }
920 }
921 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100922 TRACE("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000923}
924
Ben Murdoch097c5b22016-05-18 11:27:45 +0100925bool EscapeStatusAnalysis::IsNotReachable(Node* node) {
926 if (node->id() >= aliases_.size()) {
927 return false;
928 }
929 return aliases_[node->id()] == kNotReachable;
930}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931
932void EscapeAnalysis::RunObjectAnalysis() {
933 virtual_states_.resize(graph()->NodeCount());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100934 ZoneDeque<Node*> queue(zone());
935 queue.push_back(graph()->start());
936 ZoneVector<Node*> danglers(zone());
937 while (!queue.empty()) {
938 Node* node = queue.back();
939 queue.pop_back();
Ben Murdochc5610432016-08-08 18:44:38 +0100940 status_analysis_->SetInQueue(node->id(), false);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100941 if (Process(node)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000942 for (Edge edge : node->use_edges()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100943 Node* use = edge.from();
Ben Murdochc5610432016-08-08 18:44:38 +0100944 if (status_analysis_->IsNotReachable(use)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100945 continue;
946 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000947 if (NodeProperties::IsEffectEdge(edge)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100948 // Iteration order: depth first, but delay phis.
949 // We need DFS do avoid some duplication of VirtualStates and
950 // VirtualObjects, and we want to delay phis to improve performance.
951 if (use->opcode() == IrOpcode::kEffectPhi) {
Ben Murdochc5610432016-08-08 18:44:38 +0100952 if (!status_analysis_->IsInQueue(use->id())) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100953 queue.push_front(use);
954 }
955 } else if ((use->opcode() != IrOpcode::kLoadField &&
956 use->opcode() != IrOpcode::kLoadElement) ||
Ben Murdochc5610432016-08-08 18:44:38 +0100957 !status_analysis_->IsDanglingEffectNode(use)) {
958 if (!status_analysis_->IsInQueue(use->id())) {
959 status_analysis_->SetInQueue(use->id(), true);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100960 queue.push_back(use);
961 }
962 } else {
963 danglers.push_back(use);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000964 }
965 }
966 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100967 // Danglers need to be processed immediately, even if they are
968 // on the stack. Since they do not have effect outputs,
969 // we don't have to track whether they are on the stack.
970 queue.insert(queue.end(), danglers.begin(), danglers.end());
971 danglers.clear();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000972 }
973 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100974#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000975 if (FLAG_trace_turbo_escape) {
976 DebugPrint();
977 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100978#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000979}
980
Ben Murdoch097c5b22016-05-18 11:27:45 +0100981bool EscapeStatusAnalysis::IsDanglingEffectNode(Node* node) {
982 if (status_[node->id()] & kDanglingComputed) {
983 return status_[node->id()] & kDangling;
984 }
985 if (node->op()->EffectInputCount() == 0 ||
986 node->op()->EffectOutputCount() == 0 ||
987 (node->op()->EffectInputCount() == 1 &&
988 NodeProperties::GetEffectInput(node)->opcode() == IrOpcode::kStart)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000989 // The start node is used as sentinel for nodes that are in general
990 // effectful, but of which an analysis has determined that they do not
991 // produce effects in this instance. We don't consider these nodes dangling.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100992 status_[node->id()] |= kDanglingComputed;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000993 return false;
994 }
995 for (Edge edge : node->use_edges()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100996 Node* use = edge.from();
997 if (aliases_[use->id()] == kNotReachable) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000998 if (NodeProperties::IsEffectEdge(edge)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100999 status_[node->id()] |= kDanglingComputed;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001000 return false;
1001 }
1002 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001003 status_[node->id()] |= kDanglingComputed | kDangling;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001004 return true;
1005}
1006
Ben Murdoch097c5b22016-05-18 11:27:45 +01001007bool EscapeStatusAnalysis::IsEffectBranchPoint(Node* node) {
1008 if (status_[node->id()] & kBranchPointComputed) {
1009 return status_[node->id()] & kBranchPoint;
1010 }
1011 int count = 0;
1012 for (Edge edge : node->use_edges()) {
1013 Node* use = edge.from();
1014 if (aliases_[use->id()] == kNotReachable) continue;
1015 if (NodeProperties::IsEffectEdge(edge)) {
1016 if ((use->opcode() == IrOpcode::kLoadField ||
1017 use->opcode() == IrOpcode::kLoadElement ||
1018 use->opcode() == IrOpcode::kLoad) &&
1019 IsDanglingEffectNode(use))
1020 continue;
1021 if (++count > 1) {
1022 status_[node->id()] |= kBranchPointComputed | kBranchPoint;
1023 return true;
1024 }
1025 }
1026 }
1027 status_[node->id()] |= kBranchPointComputed;
1028 return false;
1029}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001030
1031bool EscapeAnalysis::Process(Node* node) {
1032 switch (node->opcode()) {
1033 case IrOpcode::kAllocate:
1034 ProcessAllocation(node);
1035 break;
1036 case IrOpcode::kBeginRegion:
1037 ForwardVirtualState(node);
1038 break;
1039 case IrOpcode::kFinishRegion:
1040 ProcessFinishRegion(node);
1041 break;
1042 case IrOpcode::kStoreField:
1043 ProcessStoreField(node);
1044 break;
1045 case IrOpcode::kLoadField:
1046 ProcessLoadField(node);
1047 break;
1048 case IrOpcode::kStoreElement:
1049 ProcessStoreElement(node);
1050 break;
1051 case IrOpcode::kLoadElement:
1052 ProcessLoadElement(node);
1053 break;
1054 case IrOpcode::kStart:
1055 ProcessStart(node);
1056 break;
1057 case IrOpcode::kEffectPhi:
1058 return ProcessEffectPhi(node);
1059 break;
1060 default:
1061 if (node->op()->EffectInputCount() > 0) {
1062 ForwardVirtualState(node);
1063 }
1064 ProcessAllocationUsers(node);
1065 break;
1066 }
1067 return true;
1068}
1069
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001070void EscapeAnalysis::ProcessAllocationUsers(Node* node) {
1071 for (Edge edge : node->input_edges()) {
1072 Node* input = edge.to();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001073 Node* use = edge.from();
1074 if (edge.index() >= use->op()->ValueInputCount() +
1075 OperatorProperties::GetContextInputCount(use->op()))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 continue;
1077 switch (node->opcode()) {
1078 case IrOpcode::kStoreField:
1079 case IrOpcode::kLoadField:
1080 case IrOpcode::kStoreElement:
1081 case IrOpcode::kLoadElement:
1082 case IrOpcode::kFrameState:
1083 case IrOpcode::kStateValues:
1084 case IrOpcode::kReferenceEqual:
1085 case IrOpcode::kFinishRegion:
Ben Murdoch097c5b22016-05-18 11:27:45 +01001086 case IrOpcode::kObjectIsSmi:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001087 break;
1088 default:
1089 VirtualState* state = virtual_states_[node->id()];
Ben Murdoch097c5b22016-05-18 11:27:45 +01001090 if (VirtualObject* obj =
1091 GetVirtualObject(state, ResolveReplacement(input))) {
1092 if (!obj->AllFieldsClear()) {
1093 obj = CopyForModificationAt(obj, state, node);
1094 obj->ClearAllFields();
Ben Murdochc5610432016-08-08 18:44:38 +01001095 TRACE("Cleared all fields of @%d:#%d\n",
1096 status_analysis_->GetAlias(obj->id()), obj->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001097 }
1098 }
1099 break;
1100 }
1101 }
1102}
1103
Ben Murdoch097c5b22016-05-18 11:27:45 +01001104VirtualState* EscapeAnalysis::CopyForModificationAt(VirtualState* state,
1105 Node* node) {
1106 if (state->owner() != node) {
1107 VirtualState* new_state = new (zone()) VirtualState(node, *state);
1108 virtual_states_[node->id()] = new_state;
1109 TRACE("Copying virtual state %p to new state %p at node %s#%d\n",
1110 static_cast<void*>(state), static_cast<void*>(new_state),
1111 node->op()->mnemonic(), node->id());
1112 return new_state;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001113 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001114 return state;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001115}
1116
Ben Murdoch097c5b22016-05-18 11:27:45 +01001117VirtualObject* EscapeAnalysis::CopyForModificationAt(VirtualObject* obj,
1118 VirtualState* state,
1119 Node* node) {
1120 if (obj->NeedCopyForModification()) {
1121 state = CopyForModificationAt(state, node);
Ben Murdochc5610432016-08-08 18:44:38 +01001122 return state->Copy(obj, status_analysis_->GetAlias(obj->id()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001123 }
1124 return obj;
1125}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001126
1127void EscapeAnalysis::ForwardVirtualState(Node* node) {
1128 DCHECK_EQ(node->op()->EffectInputCount(), 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001129#ifdef DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001130 if (node->opcode() != IrOpcode::kLoadField &&
1131 node->opcode() != IrOpcode::kLoadElement &&
Ben Murdochc5610432016-08-08 18:44:38 +01001132 node->opcode() != IrOpcode::kLoad &&
1133 status_analysis_->IsDanglingEffectNode(node)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001134 PrintF("Dangeling effect node: #%d (%s)\n", node->id(),
1135 node->op()->mnemonic());
1136 UNREACHABLE();
1137 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001138#endif // DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001139 Node* effect = NodeProperties::GetEffectInput(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001140 DCHECK_NOT_NULL(virtual_states_[effect->id()]);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001141 if (virtual_states_[node->id()]) {
1142 virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()],
1143 zone());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001144 } else {
1145 virtual_states_[node->id()] = virtual_states_[effect->id()];
Ben Murdoch097c5b22016-05-18 11:27:45 +01001146 TRACE("Forwarding object state %p from %s#%d to %s#%d",
1147 static_cast<void*>(virtual_states_[effect->id()]),
1148 effect->op()->mnemonic(), effect->id(), node->op()->mnemonic(),
1149 node->id());
Ben Murdochc5610432016-08-08 18:44:38 +01001150 if (status_analysis_->IsEffectBranchPoint(effect) ||
Ben Murdoch097c5b22016-05-18 11:27:45 +01001151 OperatorProperties::GetFrameStateInputCount(node->op()) > 0) {
1152 virtual_states_[node->id()]->SetCopyRequired();
1153 TRACE(", effect input %s#%d is branch point", effect->op()->mnemonic(),
1154 effect->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001155 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001156 TRACE("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001157 }
1158}
1159
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001160void EscapeAnalysis::ProcessStart(Node* node) {
1161 DCHECK_EQ(node->opcode(), IrOpcode::kStart);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001162 virtual_states_[node->id()] =
Ben Murdochc5610432016-08-08 18:44:38 +01001163 new (zone()) VirtualState(node, zone(), status_analysis_->AliasCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001164}
1165
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001166bool EscapeAnalysis::ProcessEffectPhi(Node* node) {
1167 DCHECK_EQ(node->opcode(), IrOpcode::kEffectPhi);
1168 bool changed = false;
1169
1170 VirtualState* mergeState = virtual_states_[node->id()];
1171 if (!mergeState) {
Ben Murdochc5610432016-08-08 18:44:38 +01001172 mergeState =
1173 new (zone()) VirtualState(node, zone(), status_analysis_->AliasCount());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001174 virtual_states_[node->id()] = mergeState;
1175 changed = true;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001176 TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(),
1177 static_cast<void*>(mergeState));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001178 }
1179
1180 cache_->Clear();
1181
Ben Murdoch097c5b22016-05-18 11:27:45 +01001182 TRACE("At Effect Phi #%d, merging states into %p:", node->id(),
1183 static_cast<void*>(mergeState));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001184
1185 for (int i = 0; i < node->op()->EffectInputCount(); ++i) {
1186 Node* input = NodeProperties::GetEffectInput(node, i);
1187 VirtualState* state = virtual_states_[input->id()];
1188 if (state) {
1189 cache_->states().push_back(state);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001190 if (state == mergeState) {
Ben Murdochc5610432016-08-08 18:44:38 +01001191 mergeState = new (zone())
1192 VirtualState(node, zone(), status_analysis_->AliasCount());
Ben Murdoch097c5b22016-05-18 11:27:45 +01001193 virtual_states_[node->id()] = mergeState;
1194 changed = true;
1195 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001196 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001197 TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(),
1198 input->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001199 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001200 TRACE("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001201
1202 if (cache_->states().size() == 0) {
1203 return changed;
1204 }
1205
Ben Murdoch097c5b22016-05-18 11:27:45 +01001206 changed =
1207 mergeState->MergeFrom(cache_, zone(), graph(), common(), node) || changed;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001208
Ben Murdoch097c5b22016-05-18 11:27:45 +01001209 TRACE("Merge %s the node.\n", changed ? "changed" : "did not change");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001210
1211 if (changed) {
Ben Murdochc5610432016-08-08 18:44:38 +01001212 status_analysis_->ResizeStatusVector();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001213 }
1214 return changed;
1215}
1216
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001217void EscapeAnalysis::ProcessAllocation(Node* node) {
1218 DCHECK_EQ(node->opcode(), IrOpcode::kAllocate);
1219 ForwardVirtualState(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001220 VirtualState* state = virtual_states_[node->id()];
Ben Murdochc5610432016-08-08 18:44:38 +01001221 Alias alias = status_analysis_->GetAlias(node->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001222
1223 // Check if we have already processed this node.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001224 if (state->VirtualObjectFromAlias(alias)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001225 return;
1226 }
1227
Ben Murdoch097c5b22016-05-18 11:27:45 +01001228 if (state->owner()->opcode() == IrOpcode::kEffectPhi) {
1229 state = CopyForModificationAt(state, node);
1230 }
1231
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 NumberMatcher size(node->InputAt(0));
1233 DCHECK(node->InputAt(0)->opcode() != IrOpcode::kInt32Constant &&
1234 node->InputAt(0)->opcode() != IrOpcode::kInt64Constant &&
1235 node->InputAt(0)->opcode() != IrOpcode::kFloat32Constant &&
1236 node->InputAt(0)->opcode() != IrOpcode::kFloat64Constant);
1237 if (size.HasValue()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001238 VirtualObject* obj = new (zone()) VirtualObject(
1239 node->id(), state, zone(), size.Value() / kPointerSize, false);
1240 state->SetVirtualObject(alias, obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001241 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001242 state->SetVirtualObject(
1243 alias, new (zone()) VirtualObject(node->id(), state, zone()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001244 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001245}
1246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001247void EscapeAnalysis::ProcessFinishRegion(Node* node) {
1248 DCHECK_EQ(node->opcode(), IrOpcode::kFinishRegion);
1249 ForwardVirtualState(node);
1250 Node* allocation = NodeProperties::GetValueInput(node, 0);
1251 if (allocation->opcode() == IrOpcode::kAllocate) {
1252 VirtualState* state = virtual_states_[node->id()];
Ben Murdochc5610432016-08-08 18:44:38 +01001253 VirtualObject* obj =
1254 state->VirtualObjectFromAlias(status_analysis_->GetAlias(node->id()));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001255 DCHECK_NOT_NULL(obj);
1256 obj->SetInitialized();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 }
1258}
1259
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260Node* EscapeAnalysis::replacement(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +01001261 if (node->id() >= replacements_.size()) return nullptr;
1262 return replacements_[node->id()];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263}
1264
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001265bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) {
1266 bool changed = replacements_[node->id()] != rep;
1267 replacements_[node->id()] = rep;
1268 return changed;
1269}
1270
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001271bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node,
1272 Node* rep) {
1273 if (SetReplacement(node, rep)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001274 if (rep) {
1275 TRACE("Replacement of #%d is #%d (%s)\n", node->id(), rep->id(),
1276 rep->op()->mnemonic());
1277 } else {
1278 TRACE("Replacement of #%d cleared\n", node->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001279 }
1280 return true;
1281 }
1282 return false;
1283}
1284
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001285Node* EscapeAnalysis::ResolveReplacement(Node* node) {
1286 while (replacement(node)) {
1287 node = replacement(node);
1288 }
1289 return node;
1290}
1291
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001292Node* EscapeAnalysis::GetReplacement(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +01001293 Node* result = nullptr;
1294 while (replacement(node)) {
1295 node = result = replacement(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001296 }
Ben Murdochc5610432016-08-08 18:44:38 +01001297 return result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001298}
1299
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001300bool EscapeAnalysis::IsVirtual(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +01001301 if (node->id() >= status_analysis_->GetStatusVectorSize()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001302 return false;
1303 }
Ben Murdochc5610432016-08-08 18:44:38 +01001304 return status_analysis_->IsVirtual(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001305}
1306
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001307bool EscapeAnalysis::IsEscaped(Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +01001308 if (node->id() >= status_analysis_->GetStatusVectorSize()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001309 return false;
1310 }
Ben Murdochc5610432016-08-08 18:44:38 +01001311 return status_analysis_->IsEscaped(node);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001312}
1313
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001314bool EscapeAnalysis::CompareVirtualObjects(Node* left, Node* right) {
1315 DCHECK(IsVirtual(left) && IsVirtual(right));
1316 left = ResolveReplacement(left);
1317 right = ResolveReplacement(right);
1318 if (IsEquivalentPhi(left, right)) {
1319 return true;
1320 }
1321 return false;
1322}
1323
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001324int EscapeAnalysis::OffsetFromAccess(Node* node) {
1325 DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0);
1326 return OpParameter<FieldAccess>(node).offset / kPointerSize;
1327}
1328
Ben Murdoch097c5b22016-05-18 11:27:45 +01001329void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001330 VirtualState* state) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001331 TRACE("Load #%d from phi #%d", load->id(), from->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001332
1333 cache_->fields().clear();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001334 for (int i = 0; i < load->op()->ValueInputCount(); ++i) {
1335 Node* input = NodeProperties::GetValueInput(load, i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001336 cache_->fields().push_back(input);
1337 }
1338
Ben Murdoch097c5b22016-05-18 11:27:45 +01001339 cache_->LoadVirtualObjectsForFieldsFrom(state,
Ben Murdochc5610432016-08-08 18:44:38 +01001340 status_analysis_->GetAliasMap());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001341 if (cache_->objects().size() == cache_->fields().size()) {
1342 cache_->GetFields(offset);
1343 if (cache_->fields().size() == cache_->objects().size()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001344 Node* rep = replacement(load);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001345 if (!rep || !IsEquivalentPhi(rep, cache_->fields())) {
1346 int value_input_count = static_cast<int>(cache_->fields().size());
1347 cache_->fields().push_back(NodeProperties::GetControlInput(from));
1348 Node* phi = graph()->NewNode(
1349 common()->Phi(MachineRepresentation::kTagged, value_input_count),
1350 value_input_count + 1, &cache_->fields().front());
Ben Murdochc5610432016-08-08 18:44:38 +01001351 status_analysis_->ResizeStatusVector();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001352 SetReplacement(load, phi);
1353 TRACE(" got phi created.\n");
1354 } else {
1355 TRACE(" has already phi #%d.\n", rep->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001356 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001357 } else {
1358 TRACE(" has incomplete field info.\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001360 } else {
1361 TRACE(" has incomplete virtual object info.\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 }
1363}
1364
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365void EscapeAnalysis::ProcessLoadField(Node* node) {
1366 DCHECK_EQ(node->opcode(), IrOpcode::kLoadField);
1367 ForwardVirtualState(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001368 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369 VirtualState* state = virtual_states_[node->id()];
Ben Murdoch097c5b22016-05-18 11:27:45 +01001370 if (VirtualObject* object = GetVirtualObject(state, from)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 int offset = OffsetFromAccess(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001372 if (!object->IsTracked() ||
1373 static_cast<size_t>(offset) >= object->field_count()) {
1374 return;
1375 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001376 Node* value = object->GetField(offset);
1377 if (value) {
1378 value = ResolveReplacement(value);
1379 }
1380 // Record that the load has this alias.
1381 UpdateReplacement(state, node, value);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001382 } else if (from->opcode() == IrOpcode::kPhi &&
1383 OpParameter<FieldAccess>(node).offset % kPointerSize == 0) {
1384 int offset = OffsetFromAccess(node);
1385 // Only binary phis are supported for now.
1386 ProcessLoadFromPhi(offset, from, node, state);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 } else {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001388 UpdateReplacement(state, node, nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 }
1390}
1391
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001392void EscapeAnalysis::ProcessLoadElement(Node* node) {
1393 DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement);
1394 ForwardVirtualState(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001395 Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 VirtualState* state = virtual_states_[node->id()];
1397 Node* index_node = node->InputAt(1);
1398 NumberMatcher index(index_node);
1399 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant &&
1400 index_node->opcode() != IrOpcode::kInt64Constant &&
1401 index_node->opcode() != IrOpcode::kFloat32Constant &&
1402 index_node->opcode() != IrOpcode::kFloat64Constant);
1403 ElementAccess access = OpParameter<ElementAccess>(node);
1404 if (index.HasValue()) {
1405 int offset = index.Value() + access.header_size / kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001406 if (VirtualObject* object = GetVirtualObject(state, from)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
1408 kPointerSizeLog2);
1409 CHECK_EQ(access.header_size % kPointerSize, 0);
1410
Ben Murdoch097c5b22016-05-18 11:27:45 +01001411 if (!object->IsTracked() ||
1412 static_cast<size_t>(offset) >= object->field_count()) {
1413 return;
1414 }
1415
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001416 Node* value = object->GetField(offset);
1417 if (value) {
1418 value = ResolveReplacement(value);
1419 }
1420 // Record that the load has this alias.
1421 UpdateReplacement(state, node, value);
1422 } else if (from->opcode() == IrOpcode::kPhi) {
1423 ElementAccess access = OpParameter<ElementAccess>(node);
1424 int offset = index.Value() + access.header_size / kPointerSize;
1425 ProcessLoadFromPhi(offset, from, node, state);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001426 } else {
1427 UpdateReplacement(state, node, nullptr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001428 }
1429 } else {
1430 // We have a load from a non-const index, cannot eliminate object.
Ben Murdochc5610432016-08-08 18:44:38 +01001431 if (status_analysis_->SetEscaped(from)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001432 TRACE(
1433 "Setting #%d (%s) to escaped because load element #%d from non-const "
1434 "index #%d (%s)\n",
1435 from->id(), from->op()->mnemonic(), node->id(), index_node->id(),
1436 index_node->op()->mnemonic());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001437 }
1438 }
1439}
1440
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441void EscapeAnalysis::ProcessStoreField(Node* node) {
1442 DCHECK_EQ(node->opcode(), IrOpcode::kStoreField);
1443 ForwardVirtualState(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001444 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001445 VirtualState* state = virtual_states_[node->id()];
Ben Murdoch097c5b22016-05-18 11:27:45 +01001446 VirtualObject* obj = GetVirtualObject(state, to);
1447 int offset = OffsetFromAccess(node);
1448 if (obj && obj->IsTracked() &&
1449 static_cast<size_t>(offset) < obj->field_count()) {
1450 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 1));
1451 if (obj->GetField(offset) != val) {
1452 obj = CopyForModificationAt(obj, state, node);
1453 obj->SetField(offset, val);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001454 }
1455 }
1456}
1457
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458void EscapeAnalysis::ProcessStoreElement(Node* node) {
1459 DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement);
1460 ForwardVirtualState(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001461 Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001462 Node* index_node = node->InputAt(1);
1463 NumberMatcher index(index_node);
1464 DCHECK(index_node->opcode() != IrOpcode::kInt32Constant &&
1465 index_node->opcode() != IrOpcode::kInt64Constant &&
1466 index_node->opcode() != IrOpcode::kFloat32Constant &&
1467 index_node->opcode() != IrOpcode::kFloat64Constant);
1468 ElementAccess access = OpParameter<ElementAccess>(node);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001469 VirtualState* state = virtual_states_[node->id()];
1470 VirtualObject* obj = GetVirtualObject(state, to);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001471 if (index.HasValue()) {
1472 int offset = index.Value() + access.header_size / kPointerSize;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001473 if (obj && obj->IsTracked() &&
1474 static_cast<size_t>(offset) < obj->field_count()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001475 CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()),
1476 kPointerSizeLog2);
1477 CHECK_EQ(access.header_size % kPointerSize, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001478 Node* val = ResolveReplacement(NodeProperties::GetValueInput(node, 2));
1479 if (obj->GetField(offset) != val) {
1480 obj = CopyForModificationAt(obj, state, node);
1481 obj->SetField(offset, val);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001482 }
1483 }
1484 } else {
1485 // We have a store to a non-const index, cannot eliminate object.
Ben Murdochc5610432016-08-08 18:44:38 +01001486 if (status_analysis_->SetEscaped(to)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001487 TRACE(
1488 "Setting #%d (%s) to escaped because store element #%d to non-const "
1489 "index #%d (%s)\n",
1490 to->id(), to->op()->mnemonic(), node->id(), index_node->id(),
1491 index_node->op()->mnemonic());
1492 }
1493 if (obj && obj->IsTracked()) {
1494 if (!obj->AllFieldsClear()) {
1495 obj = CopyForModificationAt(obj, state, node);
1496 obj->ClearAllFields();
Ben Murdochc5610432016-08-08 18:44:38 +01001497 TRACE("Cleared all fields of @%d:#%d\n",
1498 status_analysis_->GetAlias(obj->id()), obj->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001499 }
1500 }
1501 }
1502}
1503
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) {
1505 if ((node->opcode() == IrOpcode::kFinishRegion ||
1506 node->opcode() == IrOpcode::kAllocate) &&
1507 IsVirtual(node)) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001508 if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()],
1509 ResolveReplacement(node))) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001510 if (Node* object_state = vobj->GetObjectState()) {
1511 return object_state;
1512 } else {
1513 cache_->fields().clear();
1514 for (size_t i = 0; i < vobj->field_count(); ++i) {
1515 if (Node* field = vobj->GetField(i)) {
1516 cache_->fields().push_back(field);
1517 }
1518 }
1519 int input_count = static_cast<int>(cache_->fields().size());
1520 Node* new_object_state =
1521 graph()->NewNode(common()->ObjectState(input_count, vobj->id()),
1522 input_count, &cache_->fields().front());
1523 vobj->SetObjectState(new_object_state);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001524 TRACE(
1525 "Creating object state #%d for vobj %p (from node #%d) at effect "
1526 "#%d\n",
1527 new_object_state->id(), static_cast<void*>(vobj), node->id(),
1528 effect->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 // Now fix uses of other objects.
1530 for (size_t i = 0; i < vobj->field_count(); ++i) {
1531 if (Node* field = vobj->GetField(i)) {
1532 if (Node* field_object_state =
1533 GetOrCreateObjectState(effect, field)) {
1534 NodeProperties::ReplaceValueInput(
1535 new_object_state, field_object_state, static_cast<int>(i));
1536 }
1537 }
1538 }
1539 return new_object_state;
1540 }
1541 }
1542 }
1543 return nullptr;
1544}
1545
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001546void EscapeAnalysis::DebugPrintState(VirtualState* state) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001547 PrintF("Dumping virtual state %p\n", static_cast<void*>(state));
Ben Murdochc5610432016-08-08 18:44:38 +01001548 for (Alias alias = 0; alias < status_analysis_->AliasCount(); ++alias) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001549 if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) {
Ben Murdochc5610432016-08-08 18:44:38 +01001550 PrintF(" Alias @%d: Object #%d with %zu fields\n", alias, object->id(),
1551 object->field_count());
1552 for (size_t i = 0; i < object->field_count(); ++i) {
1553 if (Node* f = object->GetField(i)) {
1554 PrintF(" Field %zu = #%d (%s)\n", i, f->id(), f->op()->mnemonic());
1555 }
1556 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557 }
1558 }
1559}
1560
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001561void EscapeAnalysis::DebugPrint() {
1562 ZoneVector<VirtualState*> object_states(zone());
1563 for (NodeId id = 0; id < virtual_states_.size(); id++) {
1564 if (VirtualState* states = virtual_states_[id]) {
1565 if (std::find(object_states.begin(), object_states.end(), states) ==
1566 object_states.end()) {
1567 object_states.push_back(states);
1568 }
1569 }
1570 }
1571 for (size_t n = 0; n < object_states.size(); n++) {
1572 DebugPrintState(object_states[n]);
1573 }
1574}
1575
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001576VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state,
1577 Node* node) {
Ben Murdochc5610432016-08-08 18:44:38 +01001578 if (node->id() >= status_analysis_->GetAliasMap().size()) return nullptr;
1579 Alias alias = status_analysis_->GetAlias(node->id());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 if (alias >= state->size()) return nullptr;
1581 return state->VirtualObjectFromAlias(alias);
1582}
1583
Ben Murdoch097c5b22016-05-18 11:27:45 +01001584bool EscapeAnalysis::ExistsVirtualAllocate() {
Ben Murdochc5610432016-08-08 18:44:38 +01001585 for (size_t id = 0; id < status_analysis_->GetAliasMap().size(); ++id) {
1586 Alias alias = status_analysis_->GetAlias(static_cast<NodeId>(id));
Ben Murdoch097c5b22016-05-18 11:27:45 +01001587 if (alias < EscapeStatusAnalysis::kUntrackable) {
Ben Murdochc5610432016-08-08 18:44:38 +01001588 if (status_analysis_->IsVirtual(static_cast<int>(id))) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001589 return true;
1590 }
1591 }
1592 }
1593 return false;
1594}
1595
Ben Murdochc5610432016-08-08 18:44:38 +01001596Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); }
1597
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001598} // namespace compiler
1599} // namespace internal
1600} // namespace v8