| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | 
 | 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 |  | 
 | 23 | namespace v8 { | 
 | 24 | namespace internal { | 
 | 25 | namespace compiler { | 
 | 26 |  | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 27 | typedef NodeId Alias; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 28 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 29 | #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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 38 | // EscapeStatusAnalysis determines for each allocation whether it escapes. | 
 | 39 | class 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 |  | 
 | 120 | DEFINE_OPERATORS_FOR_FLAGS(EscapeStatusAnalysis::StatusFlags) | 
 | 121 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 122 | const Alias EscapeStatusAnalysis::kNotReachable = | 
 | 123 |     std::numeric_limits<Alias>::max(); | 
 | 124 | const Alias EscapeStatusAnalysis::kUntrackable = | 
 | 125 |     std::numeric_limits<Alias>::max() - 1; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 126 |  | 
 | 127 | class VirtualObject : public ZoneObject { | 
 | 128 |  public: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 129 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 138 |       : id_(id), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 139 |         status_(kInitial), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 140 |         fields_(zone), | 
 | 141 |         phi_(zone), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 142 |         object_state_(nullptr), | 
 | 143 |         owner_(owner) {} | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 144 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 145 |   VirtualObject(VirtualState* owner, const VirtualObject& other) | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 146 |       : id_(other.id_), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 147 |         status_(other.status_ & ~kCopyRequired), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 148 |         fields_(other.fields_), | 
 | 149 |         phi_(other.phi_), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 150 |         object_state_(other.object_state_), | 
 | 151 |         owner_(owner) {} | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 152 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 153 |   VirtualObject(NodeId id, VirtualState* owner, Zone* zone, size_t field_number, | 
 | 154 |                 bool initialized) | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 155 |       : id_(id), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 156 |         status_(kTracked | (initialized ? kInitialized : kInitial)), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 157 |         fields_(zone), | 
 | 158 |         phi_(zone), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 159 |         object_state_(nullptr), | 
 | 160 |         owner_(owner) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 161 |     fields_.resize(field_number); | 
 | 162 |     phi_.resize(field_number, false); | 
 | 163 |   } | 
 | 164 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 165 |   Node* GetField(size_t offset) { return fields_[offset]; } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 166 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 167 |   bool IsCreatedPhi(size_t offset) { return phi_[offset]; } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 168 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 169 |   void SetField(size_t offset, Node* node, bool created_phi = false) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 170 |     fields_[offset] = node; | 
 | 171 |     phi_[offset] = created_phi; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 172 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 173 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 177 |  | 
 | 178 |   Node** fields_array() { return &fields_.front(); } | 
 | 179 |   size_t field_count() { return fields_.size(); } | 
 | 180 |   bool ResizeFields(size_t field_count) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 181 |     if (field_count > fields_.size()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 182 |       fields_.resize(field_count); | 
 | 183 |       phi_.resize(field_count); | 
 | 184 |       return true; | 
 | 185 |     } | 
 | 186 |     return false; | 
 | 187 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 188 |   void ClearAllFields() { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 189 |     for (size_t i = 0; i < fields_.size(); ++i) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 190 |       fields_[i] = nullptr; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 191 |       phi_[i] = false; | 
 | 192 |     } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 193 |   } | 
 | 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 201 |   } | 
 | 202 |   bool UpdateFrom(const VirtualObject& other); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 203 |   bool MergeFrom(MergeCache* cache, Node* at, Graph* graph, | 
 | 204 |                  CommonOperatorBuilder* common); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 205 |   void SetObjectState(Node* node) { object_state_ = node; } | 
 | 206 |   Node* GetObjectState() const { return object_state_; } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 207 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 215 |  | 
 | 216 |   NodeId id() const { return id_; } | 
 | 217 |   void id(NodeId id) { id_ = id; } | 
 | 218 |  | 
 | 219 |  private: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 220 |   bool MergeFields(size_t i, Node* at, MergeCache* cache, Graph* graph, | 
 | 221 |                    CommonOperatorBuilder* common); | 
 | 222 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 223 |   NodeId id_; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 224 |   StatusFlags status_; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 225 |   ZoneVector<Node*> fields_; | 
 | 226 |   ZoneVector<bool> phi_; | 
 | 227 |   Node* object_state_; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 228 |   VirtualState* owner_; | 
 | 229 |  | 
 | 230 |   DISALLOW_COPY_AND_ASSIGN(VirtualObject); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 231 | }; | 
 | 232 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 233 | DEFINE_OPERATORS_FOR_FLAGS(VirtualObject::StatusFlags) | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 234 |  | 
 | 235 | bool VirtualObject::UpdateFrom(const VirtualObject& other) { | 
 | 236 |   bool changed = status_ != other.status_; | 
 | 237 |   status_ = other.status_; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 238 |   phi_ = other.phi_; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 239 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 252 | class VirtualState : public ZoneObject { | 
 | 253 |  public: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 254 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 266 |  | 
 | 267 |   VirtualObject* VirtualObjectFromAlias(size_t alias); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 268 |   void SetVirtualObject(Alias alias, VirtualObject* state); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 269 |   bool UpdateFrom(VirtualState* state, Zone* zone); | 
 | 270 |   bool MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 271 |                  CommonOperatorBuilder* common, Node* at); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 272 |   size_t size() const { return info_.size(); } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 273 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 280 |  | 
 | 281 |  private: | 
 | 282 |   ZoneVector<VirtualObject*> info_; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 283 |   Node* owner_; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 284 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 285 |   DISALLOW_COPY_AND_ASSIGN(VirtualState); | 
 | 286 | }; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 287 |  | 
 | 288 | class MergeCache : public ZoneObject { | 
 | 289 |  public: | 
 | 290 |   explicit MergeCache(Zone* zone) | 
 | 291 |       : states_(zone), objects_(zone), fields_(zone) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 292 |     states_.reserve(5); | 
 | 293 |     objects_.reserve(5); | 
 | 294 |     fields_.reserve(5); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 295 |   } | 
 | 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 304 |   size_t LoadVirtualObjectsFromStatesFor(Alias alias); | 
 | 305 |   void LoadVirtualObjectsForFieldsFrom(VirtualState* state, | 
 | 306 |                                        const ZoneVector<Alias>& aliases); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 307 |   Node* GetFields(size_t pos); | 
 | 308 |  | 
 | 309 |  private: | 
 | 310 |   ZoneVector<VirtualState*> states_; | 
 | 311 |   ZoneVector<VirtualObject*> objects_; | 
 | 312 |   ZoneVector<Node*> fields_; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 313 |  | 
 | 314 |   DISALLOW_COPY_AND_ASSIGN(MergeCache); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 315 | }; | 
 | 316 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 317 | size_t MergeCache::LoadVirtualObjectsFromStatesFor(Alias alias) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 318 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 330 | void MergeCache::LoadVirtualObjectsForFieldsFrom( | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 331 |     VirtualState* state, const ZoneVector<Alias>& aliases) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 332 |   objects_.clear(); | 
 | 333 |   size_t max_alias = state->size(); | 
 | 334 |   for (Node* field : fields_) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 335 |     Alias alias = aliases[field->id()]; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 336 |     if (alias >= max_alias) continue; | 
 | 337 |     if (VirtualObject* obj = state->VirtualObjectFromAlias(alias)) { | 
 | 338 |       objects_.push_back(obj); | 
 | 339 |     } | 
 | 340 |   } | 
 | 341 | } | 
 | 342 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 343 | Node* MergeCache::GetFields(size_t pos) { | 
 | 344 |   fields_.clear(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 345 |   Node* rep = pos >= objects_.front()->field_count() | 
 | 346 |                   ? nullptr | 
 | 347 |                   : objects_.front()->GetField(pos); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 348 |   for (VirtualObject* obj : objects_) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 349 |     if (pos >= obj->field_count()) continue; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 350 |     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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 361 | VirtualObject* 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 370 | } | 
 | 371 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 372 | VirtualObject* VirtualState::VirtualObjectFromAlias(size_t alias) { | 
 | 373 |   return info_[alias]; | 
 | 374 | } | 
 | 375 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 376 | void VirtualState::SetVirtualObject(Alias alias, VirtualObject* obj) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 377 |   info_[alias] = obj; | 
 | 378 | } | 
 | 379 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 380 | bool VirtualState::UpdateFrom(VirtualState* from, Zone* zone) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 381 |   if (from == this) return false; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 382 |   bool changed = false; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 383 |   for (Alias alias = 0; alias < size(); ++alias) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 384 |     VirtualObject* ls = VirtualObjectFromAlias(alias); | 
 | 385 |     VirtualObject* rs = from->VirtualObjectFromAlias(alias); | 
 | 386 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 387 |     if (ls == rs || rs == nullptr) continue; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 388 |  | 
 | 389 |     if (ls == nullptr) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 390 |       ls = new (zone) VirtualObject(this, *rs); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 391 |       SetVirtualObject(alias, ls); | 
 | 392 |       changed = true; | 
 | 393 |       continue; | 
 | 394 |     } | 
 | 395 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 396 |     TRACE("  Updating fields of @%d\n", alias); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 397 |  | 
 | 398 |     changed = ls->UpdateFrom(*rs) || changed; | 
 | 399 |   } | 
 | 400 |   return false; | 
 | 401 | } | 
 | 402 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 403 | namespace { | 
 | 404 |  | 
 | 405 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 421 | bool 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 437 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 468 |     } | 
 | 469 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 470 |   return changed; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 471 | } | 
 | 472 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 473 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 500 |  | 
 | 501 | bool VirtualState::MergeFrom(MergeCache* cache, Zone* zone, Graph* graph, | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 502 |                              CommonOperatorBuilder* common, Node* at) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 503 |   DCHECK_GT(cache->states().size(), 0u); | 
 | 504 |   bool changed = false; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 505 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 515 |         } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 516 |         fields = std::min(obj->field_count(), fields); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 517 |       } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 518 |     } | 
 | 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 546 |     } else { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 547 |       if (mergeObject) { | 
 | 548 |         TRACE("  Alias %d, virtual object removed\n", alias); | 
 | 549 |         changed = true; | 
 | 550 |       } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 551 |       SetVirtualObject(alias, nullptr); | 
 | 552 |     } | 
 | 553 |   } | 
 | 554 |   return changed; | 
 | 555 | } | 
 | 556 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 557 | EscapeStatusAnalysis::EscapeStatusAnalysis(EscapeAnalysis* object_analysis, | 
 | 558 |                                            Graph* graph, Zone* zone) | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 559 |     : stack_(zone), | 
 | 560 |       object_analysis_(object_analysis), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 561 |       graph_(graph), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 562 |       status_(zone), | 
 | 563 |       next_free_alias_(0), | 
 | 564 |       status_stack_(zone), | 
 | 565 |       aliases_(zone) {} | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 566 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 567 | bool EscapeStatusAnalysis::HasEntry(Node* node) { | 
 | 568 |   return status_[node->id()] & (kTracked | kEscaped); | 
 | 569 | } | 
 | 570 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 571 | bool EscapeStatusAnalysis::IsVirtual(Node* node) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 572 |   return IsVirtual(node->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 573 | } | 
 | 574 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 575 | bool EscapeStatusAnalysis::IsVirtual(NodeId id) { | 
 | 576 |   return (status_[id] & kTracked) && !(status_[id] & kEscaped); | 
 | 577 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 578 |  | 
 | 579 | bool EscapeStatusAnalysis::IsEscaped(Node* node) { | 
 | 580 |   return status_[node->id()] & kEscaped; | 
 | 581 | } | 
 | 582 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 583 | bool EscapeStatusAnalysis::IsAllocation(Node* node) { | 
 | 584 |   return node->opcode() == IrOpcode::kAllocate || | 
 | 585 |          node->opcode() == IrOpcode::kFinishRegion; | 
 | 586 | } | 
 | 587 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 588 | bool EscapeStatusAnalysis::SetEscaped(Node* node) { | 
 | 589 |   bool changed = !(status_[node->id()] & kEscaped); | 
 | 590 |   status_[node->id()] |= kEscaped | kTracked; | 
 | 591 |   return changed; | 
 | 592 | } | 
 | 593 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 594 | bool EscapeStatusAnalysis::IsInQueue(NodeId id) { | 
 | 595 |   return status_[id] & kInQueue; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 596 | } | 
 | 597 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 598 | void EscapeStatusAnalysis::SetInQueue(NodeId id, bool on_stack) { | 
 | 599 |   if (on_stack) { | 
 | 600 |     status_[id] |= kInQueue; | 
 | 601 |   } else { | 
 | 602 |     status_[id] &= ~kInQueue; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 603 |   } | 
 | 604 | } | 
 | 605 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 606 | void EscapeStatusAnalysis::ResizeStatusVector() { | 
 | 607 |   if (status_.size() <= graph()->NodeCount()) { | 
 | 608 |     status_.resize(graph()->NodeCount() * 1.1, kUnknown); | 
 | 609 |   } | 
 | 610 | } | 
 | 611 |  | 
 | 612 | size_t EscapeStatusAnalysis::GetStatusVectorSize() { return status_.size(); } | 
 | 613 |  | 
 | 614 | void 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 |  | 
 | 625 | void 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 632 |  | 
 | 633 | void EscapeStatusAnalysis::RevisitInputs(Node* node) { | 
 | 634 |   for (Edge edge : node->input_edges()) { | 
 | 635 |     Node* input = edge.to(); | 
 | 636 |     if (!(status_[input->id()] & kOnStack)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 637 |       status_stack_.push_back(input); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 638 |       status_[input->id()] |= kOnStack; | 
 | 639 |     } | 
 | 640 |   } | 
 | 641 | } | 
 | 642 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 643 | void EscapeStatusAnalysis::RevisitUses(Node* node) { | 
 | 644 |   for (Edge edge : node->use_edges()) { | 
 | 645 |     Node* use = edge.from(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 646 |     if (!(status_[use->id()] & kOnStack) && !IsNotReachable(use)) { | 
 | 647 |       status_stack_.push_back(use); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 648 |       status_[use->id()] |= kOnStack; | 
 | 649 |     } | 
 | 650 |   } | 
 | 651 | } | 
 | 652 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 653 | void 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 675 |       RevisitUses(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 676 |       break; | 
 | 677 |     } | 
 | 678 |     case IrOpcode::kPhi: | 
 | 679 |       if (!HasEntry(node)) { | 
 | 680 |         status_[node->id()] |= kTracked; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 681 |         RevisitUses(node); | 
 | 682 |       } | 
 | 683 |       if (!IsAllocationPhi(node) && SetEscaped(node)) { | 
 | 684 |         RevisitInputs(node); | 
 | 685 |         RevisitUses(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 686 |       } | 
 | 687 |       CheckUsesForEscape(node); | 
 | 688 |     default: | 
 | 689 |       break; | 
 | 690 |   } | 
 | 691 | } | 
 | 692 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 693 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 703 | void 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 710 |     TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", | 
 | 711 |           val->id(), val->op()->mnemonic(), to->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 712 |   } | 
 | 713 | } | 
 | 714 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 715 | void 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 722 |     TRACE("Setting #%d (%s) to escaped because of store to field of #%d\n", | 
 | 723 |           val->id(), val->op()->mnemonic(), to->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 724 |   } | 
 | 725 | } | 
 | 726 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 727 | void EscapeStatusAnalysis::ProcessAllocate(Node* node) { | 
 | 728 |   DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 
 | 729 |   if (!HasEntry(node)) { | 
 | 730 |     status_[node->id()] |= kTracked; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 731 |     TRACE("Created status entry for node #%d (%s)\n", node->id(), | 
 | 732 |           node->op()->mnemonic()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 733 |     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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 738 |     RevisitUses(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 739 |     if (!size.HasValue() && SetEscaped(node)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 740 |       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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 743 |       return; | 
 | 744 |     } | 
 | 745 |   } | 
 | 746 |   if (CheckUsesForEscape(node, true)) { | 
 | 747 |     RevisitUses(node); | 
 | 748 |   } | 
 | 749 | } | 
 | 750 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 751 | bool EscapeStatusAnalysis::CheckUsesForEscape(Node* uses, Node* rep, | 
 | 752 |                                               bool phi_escaping) { | 
 | 753 |   for (Edge edge : uses->use_edges()) { | 
 | 754 |     Node* use = edge.from(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 755 |     if (IsNotReachable(use)) continue; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 756 |     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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 762 |           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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 767 |           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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 779 |           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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 784 |           return true; | 
 | 785 |         } | 
 | 786 |         break; | 
 | 787 |       case IrOpcode::kObjectIsSmi: | 
 | 788 |         if (!IsAllocation(rep) && SetEscaped(rep)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 789 |           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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 796 |       case IrOpcode::kTypeGuard: | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 797 |         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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 801 |           return true; | 
 | 802 |         } | 
 | 803 |         break; | 
 | 804 |       default: | 
 | 805 |         if (use->op()->EffectInputCount() == 0 && | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 806 |             uses->op()->EffectInputCount() > 0 && | 
 | 807 |             !IrOpcode::IsJsOpcode(use->opcode())) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 808 |           TRACE("Encountered unaccounted use by #%d (%s)\n", use->id(), | 
 | 809 |                 use->op()->mnemonic()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 810 |           UNREACHABLE(); | 
 | 811 |         } | 
 | 812 |         if (SetEscaped(rep)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 813 |           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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 816 |           return true; | 
 | 817 |         } | 
 | 818 |     } | 
 | 819 |   } | 
 | 820 |   return false; | 
 | 821 | } | 
 | 822 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 823 | void 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 834 | void 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 843 | EscapeAnalysis::EscapeAnalysis(Graph* graph, CommonOperatorBuilder* common, | 
 | 844 |                                Zone* zone) | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 845 |     : zone_(zone), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 846 |       common_(common), | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 847 |       status_analysis_(new (zone) EscapeStatusAnalysis(this, graph, zone)), | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 848 |       virtual_states_(zone), | 
 | 849 |       replacements_(zone), | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 850 |       cache_(nullptr) {} | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 851 |  | 
 | 852 | EscapeAnalysis::~EscapeAnalysis() {} | 
 | 853 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 854 | void EscapeAnalysis::Run() { | 
 | 855 |   replacements_.resize(graph()->NodeCount()); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 856 |   status_analysis_->AssignAliases(); | 
 | 857 |   if (status_analysis_->AliasCount() > 0) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 858 |     cache_ = new (zone()) MergeCache(zone()); | 
 | 859 |     replacements_.resize(graph()->NodeCount()); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 860 |     status_analysis_->ResizeStatusVector(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 861 |     RunObjectAnalysis(); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 862 |     status_analysis_->RunStatusAnalysis(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 863 |   } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 864 | } | 
 | 865 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 866 | void 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 874 |   CHECK_LT(graph()->NodeCount(), kUntrackable); | 
 | 875 |   aliases_.resize(graph()->NodeCount(), kNotReachable); | 
 | 876 |   aliases_[graph()->end()->id()] = kUntrackable; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 877 |   status_stack_.reserve(8); | 
 | 878 |   TRACE("Discovering trackable nodes"); | 
 | 879 |   while (!stack_.empty()) { | 
 | 880 |     Node* node = stack_.back(); | 
 | 881 |     stack_.pop_back(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 882 |     switch (node->opcode()) { | 
 | 883 |       case IrOpcode::kAllocate: | 
 | 884 |         if (aliases_[node->id()] >= kUntrackable) { | 
 | 885 |           aliases_[node->id()] = NextAlias(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 886 |           TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), | 
 | 887 |                 node->id()); | 
 | 888 |           EnqueueForStatusAnalysis(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 889 |         } | 
 | 890 |         break; | 
 | 891 |       case IrOpcode::kFinishRegion: { | 
 | 892 |         Node* allocate = NodeProperties::GetValueInput(node, 0); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 893 |         DCHECK_NOT_NULL(allocate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 894 |         if (allocate->opcode() == IrOpcode::kAllocate) { | 
 | 895 |           if (aliases_[allocate->id()] >= kUntrackable) { | 
 | 896 |             if (aliases_[allocate->id()] == kNotReachable) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 897 |               stack_.push_back(allocate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 898 |             } | 
 | 899 |             aliases_[allocate->id()] = NextAlias(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 900 |             TRACE(" @%d:%s#%u", aliases_[allocate->id()], | 
 | 901 |                   allocate->op()->mnemonic(), allocate->id()); | 
 | 902 |             EnqueueForStatusAnalysis(allocate); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 903 |           } | 
 | 904 |           aliases_[node->id()] = aliases_[allocate->id()]; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 905 |           TRACE(" @%d:%s#%u", aliases_[node->id()], node->op()->mnemonic(), | 
 | 906 |                 node->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 907 |         } | 
 | 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 917 |         stack_.push_back(input); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 918 |         aliases_[input->id()] = kUntrackable; | 
 | 919 |       } | 
 | 920 |     } | 
 | 921 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 922 |   TRACE("\n"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 923 | } | 
 | 924 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 925 | bool EscapeStatusAnalysis::IsNotReachable(Node* node) { | 
 | 926 |   if (node->id() >= aliases_.size()) { | 
 | 927 |     return false; | 
 | 928 |   } | 
 | 929 |   return aliases_[node->id()] == kNotReachable; | 
 | 930 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 931 |  | 
 | 932 | void EscapeAnalysis::RunObjectAnalysis() { | 
 | 933 |   virtual_states_.resize(graph()->NodeCount()); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 934 |   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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 940 |     status_analysis_->SetInQueue(node->id(), false); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 941 |     if (Process(node)) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 942 |       for (Edge edge : node->use_edges()) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 943 |         Node* use = edge.from(); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 944 |         if (status_analysis_->IsNotReachable(use)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 945 |           continue; | 
 | 946 |         } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 947 |         if (NodeProperties::IsEffectEdge(edge)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 948 |           // 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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 952 |             if (!status_analysis_->IsInQueue(use->id())) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 953 |               queue.push_front(use); | 
 | 954 |             } | 
 | 955 |           } else if ((use->opcode() != IrOpcode::kLoadField && | 
 | 956 |                       use->opcode() != IrOpcode::kLoadElement) || | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 957 |                      !status_analysis_->IsDanglingEffectNode(use)) { | 
 | 958 |             if (!status_analysis_->IsInQueue(use->id())) { | 
 | 959 |               status_analysis_->SetInQueue(use->id(), true); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 960 |               queue.push_back(use); | 
 | 961 |             } | 
 | 962 |           } else { | 
 | 963 |             danglers.push_back(use); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 964 |           } | 
 | 965 |         } | 
 | 966 |       } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 967 |       // 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 972 |     } | 
 | 973 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 974 | #ifdef DEBUG | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 975 |   if (FLAG_trace_turbo_escape) { | 
 | 976 |     DebugPrint(); | 
 | 977 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 978 | #endif | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 979 | } | 
 | 980 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 981 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 989 |     // 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 992 |     status_[node->id()] |= kDanglingComputed; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 993 |     return false; | 
 | 994 |   } | 
 | 995 |   for (Edge edge : node->use_edges()) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 996 |     Node* use = edge.from(); | 
 | 997 |     if (aliases_[use->id()] == kNotReachable) continue; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 998 |     if (NodeProperties::IsEffectEdge(edge)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 999 |       status_[node->id()] |= kDanglingComputed; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1000 |       return false; | 
 | 1001 |     } | 
 | 1002 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1003 |   status_[node->id()] |= kDanglingComputed | kDangling; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1004 |   return true; | 
 | 1005 | } | 
 | 1006 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1007 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1030 |  | 
 | 1031 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1070 | void EscapeAnalysis::ProcessAllocationUsers(Node* node) { | 
 | 1071 |   for (Edge edge : node->input_edges()) { | 
 | 1072 |     Node* input = edge.to(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1073 |     Node* use = edge.from(); | 
 | 1074 |     if (edge.index() >= use->op()->ValueInputCount() + | 
 | 1075 |                             OperatorProperties::GetContextInputCount(use->op())) | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1076 |       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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1086 |       case IrOpcode::kObjectIsSmi: | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1087 |         break; | 
 | 1088 |       default: | 
 | 1089 |         VirtualState* state = virtual_states_[node->id()]; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1090 |         if (VirtualObject* obj = | 
 | 1091 |                 GetVirtualObject(state, ResolveReplacement(input))) { | 
 | 1092 |           if (!obj->AllFieldsClear()) { | 
 | 1093 |             obj = CopyForModificationAt(obj, state, node); | 
 | 1094 |             obj->ClearAllFields(); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1095 |             TRACE("Cleared all fields of @%d:#%d\n", | 
 | 1096 |                   status_analysis_->GetAlias(obj->id()), obj->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1097 |           } | 
 | 1098 |         } | 
 | 1099 |         break; | 
 | 1100 |     } | 
 | 1101 |   } | 
 | 1102 | } | 
 | 1103 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1104 | VirtualState* 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1113 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1114 |   return state; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1115 | } | 
 | 1116 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1117 | VirtualObject* EscapeAnalysis::CopyForModificationAt(VirtualObject* obj, | 
 | 1118 |                                                      VirtualState* state, | 
 | 1119 |                                                      Node* node) { | 
 | 1120 |   if (obj->NeedCopyForModification()) { | 
 | 1121 |     state = CopyForModificationAt(state, node); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1122 |     return state->Copy(obj, status_analysis_->GetAlias(obj->id())); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1123 |   } | 
 | 1124 |   return obj; | 
 | 1125 | } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1126 |  | 
 | 1127 | void EscapeAnalysis::ForwardVirtualState(Node* node) { | 
 | 1128 |   DCHECK_EQ(node->op()->EffectInputCount(), 1); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1129 | #ifdef DEBUG | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1130 |   if (node->opcode() != IrOpcode::kLoadField && | 
 | 1131 |       node->opcode() != IrOpcode::kLoadElement && | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1132 |       node->opcode() != IrOpcode::kLoad && | 
 | 1133 |       status_analysis_->IsDanglingEffectNode(node)) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1134 |     PrintF("Dangeling effect node: #%d (%s)\n", node->id(), | 
 | 1135 |            node->op()->mnemonic()); | 
 | 1136 |     UNREACHABLE(); | 
 | 1137 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1138 | #endif  // DEBUG | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1139 |   Node* effect = NodeProperties::GetEffectInput(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1140 |   DCHECK_NOT_NULL(virtual_states_[effect->id()]); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1141 |   if (virtual_states_[node->id()]) { | 
 | 1142 |     virtual_states_[node->id()]->UpdateFrom(virtual_states_[effect->id()], | 
 | 1143 |                                             zone()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1144 |   } else { | 
 | 1145 |     virtual_states_[node->id()] = virtual_states_[effect->id()]; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1146 |     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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1150 |     if (status_analysis_->IsEffectBranchPoint(effect) || | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1151 |         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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1155 |     } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1156 |     TRACE("\n"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1157 |   } | 
 | 1158 | } | 
 | 1159 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1160 | void EscapeAnalysis::ProcessStart(Node* node) { | 
 | 1161 |   DCHECK_EQ(node->opcode(), IrOpcode::kStart); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1162 |   virtual_states_[node->id()] = | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1163 |       new (zone()) VirtualState(node, zone(), status_analysis_->AliasCount()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1164 | } | 
 | 1165 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1166 | bool 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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1172 |     mergeState = | 
 | 1173 |         new (zone()) VirtualState(node, zone(), status_analysis_->AliasCount()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1174 |     virtual_states_[node->id()] = mergeState; | 
 | 1175 |     changed = true; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1176 |     TRACE("Effect Phi #%d got new virtual state %p.\n", node->id(), | 
 | 1177 |           static_cast<void*>(mergeState)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1178 |   } | 
 | 1179 |  | 
 | 1180 |   cache_->Clear(); | 
 | 1181 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1182 |   TRACE("At Effect Phi #%d, merging states into %p:", node->id(), | 
 | 1183 |         static_cast<void*>(mergeState)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1184 |  | 
 | 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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1190 |       if (state == mergeState) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1191 |         mergeState = new (zone()) | 
 | 1192 |             VirtualState(node, zone(), status_analysis_->AliasCount()); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1193 |         virtual_states_[node->id()] = mergeState; | 
 | 1194 |         changed = true; | 
 | 1195 |       } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1196 |     } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1197 |     TRACE(" %p (from %d %s)", static_cast<void*>(state), input->id(), | 
 | 1198 |           input->op()->mnemonic()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1199 |   } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1200 |   TRACE("\n"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1201 |  | 
 | 1202 |   if (cache_->states().size() == 0) { | 
 | 1203 |     return changed; | 
 | 1204 |   } | 
 | 1205 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1206 |   changed = | 
 | 1207 |       mergeState->MergeFrom(cache_, zone(), graph(), common(), node) || changed; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1208 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1209 |   TRACE("Merge %s the node.\n", changed ? "changed" : "did not change"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1210 |  | 
 | 1211 |   if (changed) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1212 |     status_analysis_->ResizeStatusVector(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1213 |   } | 
 | 1214 |   return changed; | 
 | 1215 | } | 
 | 1216 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1217 | void EscapeAnalysis::ProcessAllocation(Node* node) { | 
 | 1218 |   DCHECK_EQ(node->opcode(), IrOpcode::kAllocate); | 
 | 1219 |   ForwardVirtualState(node); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1220 |   VirtualState* state = virtual_states_[node->id()]; | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1221 |   Alias alias = status_analysis_->GetAlias(node->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1222 |  | 
 | 1223 |   // Check if we have already processed this node. | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1224 |   if (state->VirtualObjectFromAlias(alias)) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1225 |     return; | 
 | 1226 |   } | 
 | 1227 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1228 |   if (state->owner()->opcode() == IrOpcode::kEffectPhi) { | 
 | 1229 |     state = CopyForModificationAt(state, node); | 
 | 1230 |   } | 
 | 1231 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1232 |   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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1238 |     VirtualObject* obj = new (zone()) VirtualObject( | 
 | 1239 |         node->id(), state, zone(), size.Value() / kPointerSize, false); | 
 | 1240 |     state->SetVirtualObject(alias, obj); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1241 |   } else { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1242 |     state->SetVirtualObject( | 
 | 1243 |         alias, new (zone()) VirtualObject(node->id(), state, zone())); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1244 |   } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1245 | } | 
 | 1246 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1247 | void 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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1253 |     VirtualObject* obj = | 
 | 1254 |         state->VirtualObjectFromAlias(status_analysis_->GetAlias(node->id())); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1255 |     DCHECK_NOT_NULL(obj); | 
 | 1256 |     obj->SetInitialized(); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1257 |   } | 
 | 1258 | } | 
 | 1259 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1260 | Node* EscapeAnalysis::replacement(Node* node) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1261 |   if (node->id() >= replacements_.size()) return nullptr; | 
 | 1262 |   return replacements_[node->id()]; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1263 | } | 
 | 1264 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1265 | bool EscapeAnalysis::SetReplacement(Node* node, Node* rep) { | 
 | 1266 |   bool changed = replacements_[node->id()] != rep; | 
 | 1267 |   replacements_[node->id()] = rep; | 
 | 1268 |   return changed; | 
 | 1269 | } | 
 | 1270 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1271 | bool EscapeAnalysis::UpdateReplacement(VirtualState* state, Node* node, | 
 | 1272 |                                        Node* rep) { | 
 | 1273 |   if (SetReplacement(node, rep)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1274 |     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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1279 |     } | 
 | 1280 |     return true; | 
 | 1281 |   } | 
 | 1282 |   return false; | 
 | 1283 | } | 
 | 1284 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1285 | Node* EscapeAnalysis::ResolveReplacement(Node* node) { | 
 | 1286 |   while (replacement(node)) { | 
 | 1287 |     node = replacement(node); | 
 | 1288 |   } | 
 | 1289 |   return node; | 
 | 1290 | } | 
 | 1291 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1292 | Node* EscapeAnalysis::GetReplacement(Node* node) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1293 |   Node* result = nullptr; | 
 | 1294 |   while (replacement(node)) { | 
 | 1295 |     node = result = replacement(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1296 |   } | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1297 |   return result; | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1298 | } | 
 | 1299 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1300 | bool EscapeAnalysis::IsVirtual(Node* node) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1301 |   if (node->id() >= status_analysis_->GetStatusVectorSize()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1302 |     return false; | 
 | 1303 |   } | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1304 |   return status_analysis_->IsVirtual(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1305 | } | 
 | 1306 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1307 | bool EscapeAnalysis::IsEscaped(Node* node) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1308 |   if (node->id() >= status_analysis_->GetStatusVectorSize()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1309 |     return false; | 
 | 1310 |   } | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1311 |   return status_analysis_->IsEscaped(node); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1312 | } | 
 | 1313 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1314 | bool 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1324 | int EscapeAnalysis::OffsetFromAccess(Node* node) { | 
 | 1325 |   DCHECK(OpParameter<FieldAccess>(node).offset % kPointerSize == 0); | 
 | 1326 |   return OpParameter<FieldAccess>(node).offset / kPointerSize; | 
 | 1327 | } | 
 | 1328 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1329 | void EscapeAnalysis::ProcessLoadFromPhi(int offset, Node* from, Node* load, | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1330 |                                         VirtualState* state) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1331 |   TRACE("Load #%d from phi #%d", load->id(), from->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1332 |  | 
 | 1333 |   cache_->fields().clear(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1334 |   for (int i = 0; i < load->op()->ValueInputCount(); ++i) { | 
 | 1335 |     Node* input = NodeProperties::GetValueInput(load, i); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1336 |     cache_->fields().push_back(input); | 
 | 1337 |   } | 
 | 1338 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1339 |   cache_->LoadVirtualObjectsForFieldsFrom(state, | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1340 |                                           status_analysis_->GetAliasMap()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1341 |   if (cache_->objects().size() == cache_->fields().size()) { | 
 | 1342 |     cache_->GetFields(offset); | 
 | 1343 |     if (cache_->fields().size() == cache_->objects().size()) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1344 |       Node* rep = replacement(load); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1345 |       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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1351 |         status_analysis_->ResizeStatusVector(); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1352 |         SetReplacement(load, phi); | 
 | 1353 |         TRACE(" got phi created.\n"); | 
 | 1354 |       } else { | 
 | 1355 |         TRACE(" has already phi #%d.\n", rep->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1356 |       } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1357 |     } else { | 
 | 1358 |       TRACE(" has incomplete field info.\n"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1359 |     } | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1360 |   } else { | 
 | 1361 |     TRACE(" has incomplete virtual object info.\n"); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1362 |   } | 
 | 1363 | } | 
 | 1364 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1365 | void EscapeAnalysis::ProcessLoadField(Node* node) { | 
 | 1366 |   DCHECK_EQ(node->opcode(), IrOpcode::kLoadField); | 
 | 1367 |   ForwardVirtualState(node); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1368 |   Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1369 |   VirtualState* state = virtual_states_[node->id()]; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1370 |   if (VirtualObject* object = GetVirtualObject(state, from)) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1371 |     int offset = OffsetFromAccess(node); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1372 |     if (!object->IsTracked() || | 
 | 1373 |         static_cast<size_t>(offset) >= object->field_count()) { | 
 | 1374 |       return; | 
 | 1375 |     } | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1376 |     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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1382 |   } 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1387 |   } else { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1388 |     UpdateReplacement(state, node, nullptr); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1389 |   } | 
 | 1390 | } | 
 | 1391 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1392 | void EscapeAnalysis::ProcessLoadElement(Node* node) { | 
 | 1393 |   DCHECK_EQ(node->opcode(), IrOpcode::kLoadElement); | 
 | 1394 |   ForwardVirtualState(node); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1395 |   Node* from = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1396 |   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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1406 |     if (VirtualObject* object = GetVirtualObject(state, from)) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1407 |       CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 
 | 1408 |                kPointerSizeLog2); | 
 | 1409 |       CHECK_EQ(access.header_size % kPointerSize, 0); | 
 | 1410 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1411 |       if (!object->IsTracked() || | 
 | 1412 |           static_cast<size_t>(offset) >= object->field_count()) { | 
 | 1413 |         return; | 
 | 1414 |       } | 
 | 1415 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1416 |       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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1426 |     } else { | 
 | 1427 |       UpdateReplacement(state, node, nullptr); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1428 |     } | 
 | 1429 |   } else { | 
 | 1430 |     // We have a load from a non-const index, cannot eliminate object. | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1431 |     if (status_analysis_->SetEscaped(from)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1432 |       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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1437 |     } | 
 | 1438 |   } | 
 | 1439 | } | 
 | 1440 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1441 | void EscapeAnalysis::ProcessStoreField(Node* node) { | 
 | 1442 |   DCHECK_EQ(node->opcode(), IrOpcode::kStoreField); | 
 | 1443 |   ForwardVirtualState(node); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1444 |   Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1445 |   VirtualState* state = virtual_states_[node->id()]; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1446 |   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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1454 |     } | 
 | 1455 |   } | 
 | 1456 | } | 
 | 1457 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1458 | void EscapeAnalysis::ProcessStoreElement(Node* node) { | 
 | 1459 |   DCHECK_EQ(node->opcode(), IrOpcode::kStoreElement); | 
 | 1460 |   ForwardVirtualState(node); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1461 |   Node* to = ResolveReplacement(NodeProperties::GetValueInput(node, 0)); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1462 |   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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1469 |   VirtualState* state = virtual_states_[node->id()]; | 
 | 1470 |   VirtualObject* obj = GetVirtualObject(state, to); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1471 |   if (index.HasValue()) { | 
 | 1472 |     int offset = index.Value() + access.header_size / kPointerSize; | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1473 |     if (obj && obj->IsTracked() && | 
 | 1474 |         static_cast<size_t>(offset) < obj->field_count()) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1475 |       CHECK_GE(ElementSizeLog2Of(access.machine_type.representation()), | 
 | 1476 |                kPointerSizeLog2); | 
 | 1477 |       CHECK_EQ(access.header_size % kPointerSize, 0); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1478 |       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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1482 |       } | 
 | 1483 |     } | 
 | 1484 |   } else { | 
 | 1485 |     // We have a store to a non-const index, cannot eliminate object. | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1486 |     if (status_analysis_->SetEscaped(to)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1487 |       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 Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1497 |         TRACE("Cleared all fields of @%d:#%d\n", | 
 | 1498 |               status_analysis_->GetAlias(obj->id()), obj->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1499 |       } | 
 | 1500 |     } | 
 | 1501 |   } | 
 | 1502 | } | 
 | 1503 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1504 | Node* EscapeAnalysis::GetOrCreateObjectState(Node* effect, Node* node) { | 
 | 1505 |   if ((node->opcode() == IrOpcode::kFinishRegion || | 
 | 1506 |        node->opcode() == IrOpcode::kAllocate) && | 
 | 1507 |       IsVirtual(node)) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1508 |     if (VirtualObject* vobj = GetVirtualObject(virtual_states_[effect->id()], | 
 | 1509 |                                                ResolveReplacement(node))) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1510 |       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 Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1524 |         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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1529 |         // 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1546 | void EscapeAnalysis::DebugPrintState(VirtualState* state) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1547 |   PrintF("Dumping virtual state %p\n", static_cast<void*>(state)); | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1548 |   for (Alias alias = 0; alias < status_analysis_->AliasCount(); ++alias) { | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1549 |     if (VirtualObject* object = state->VirtualObjectFromAlias(alias)) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1550 |       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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1557 |     } | 
 | 1558 |   } | 
 | 1559 | } | 
 | 1560 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1561 | void 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 Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1576 | VirtualObject* EscapeAnalysis::GetVirtualObject(VirtualState* state, | 
 | 1577 |                                                 Node* node) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1578 |   if (node->id() >= status_analysis_->GetAliasMap().size()) return nullptr; | 
 | 1579 |   Alias alias = status_analysis_->GetAlias(node->id()); | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1580 |   if (alias >= state->size()) return nullptr; | 
 | 1581 |   return state->VirtualObjectFromAlias(alias); | 
 | 1582 | } | 
 | 1583 |  | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1584 | bool EscapeAnalysis::ExistsVirtualAllocate() { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1585 |   for (size_t id = 0; id < status_analysis_->GetAliasMap().size(); ++id) { | 
 | 1586 |     Alias alias = status_analysis_->GetAlias(static_cast<NodeId>(id)); | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1587 |     if (alias < EscapeStatusAnalysis::kUntrackable) { | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1588 |       if (status_analysis_->IsVirtual(static_cast<int>(id))) { | 
| Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 1589 |         return true; | 
 | 1590 |       } | 
 | 1591 |     } | 
 | 1592 |   } | 
 | 1593 |   return false; | 
 | 1594 | } | 
 | 1595 |  | 
| Ben Murdoch | c561043 | 2016-08-08 18:44:38 +0100 | [diff] [blame^] | 1596 | Graph* EscapeAnalysis::graph() const { return status_analysis_->graph(); } | 
 | 1597 |  | 
| Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 1598 | }  // namespace compiler | 
 | 1599 | }  // namespace internal | 
 | 1600 | }  // namespace v8 |