Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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/bit-vector.h" | |
| 6 #include "src/compiler/escape-analysis.h" | |
| 7 #include "src/compiler/escape-analysis-reducer.h" | |
| 8 #include "src/compiler/graph-visualizer.h" | |
| 9 #include "src/compiler/node-properties.h" | |
| 10 #include "src/compiler/simplified-operator.h" | |
| 11 #include "src/types-inl.h" | |
| 12 #include "src/zone-containers.h" | |
| 13 #include "test/unittests/compiler/graph-unittest.h" | |
| 14 | |
| 15 namespace v8 { | |
| 16 namespace internal { | |
| 17 namespace compiler { | |
| 18 | |
| 19 class EscapeAnalysisTest : public GraphTest { | |
| 20 public: | |
| 21 EscapeAnalysisTest() | |
| 22 : simplified_(zone()), | |
| 23 jsgraph_(isolate(), graph(), nullptr, nullptr, nullptr, nullptr), | |
| 24 escape_status_(nullptr), | |
| 25 escape_objects_(nullptr), | |
| 26 effect_(graph()->start()), | |
| 27 control_(graph()->start()) {} | |
| 28 | |
| 29 ~EscapeAnalysisTest() { | |
| 30 if (escape_status_) { | |
| 31 delete escape_status_; | |
| 32 } | |
| 33 if (escape_objects_) { | |
| 34 delete escape_objects_; | |
| 35 } | |
| 36 } | |
| 37 | |
| 38 EscapeStatusAnalysis* escape_status() { return escape_status_; } | |
| 39 EscapeObjectAnalysis* escape_objects() { return escape_objects_; } | |
| 40 | |
| 41 protected: | |
| 42 void Analysis() { | |
| 43 escape_status_ = new EscapeStatusAnalysis(graph(), zone()); | |
|
Michael Starzinger
2015/11/30 10:05:39
Would it be possible to just embed these two class
sigurds
2015/11/30 13:50:24
Done.
| |
| 44 escape_status_->Run(); | |
| 45 escape_objects_ = new EscapeObjectAnalysis(graph(), common(), zone()); | |
| 46 escape_objects_->Run(); | |
| 47 } | |
| 48 | |
| 49 void Transformation() { | |
| 50 GraphReducer graph_reducer(zone(), graph()); | |
| 51 EscapeAnalysisReducer red(&graph_reducer, &jsgraph_, escape_status_, | |
| 52 escape_objects_, zone()); | |
| 53 graph_reducer.AddReducer(&red); | |
| 54 graph_reducer.ReduceGraph(); | |
| 55 } | |
| 56 | |
| 57 // ---------------------------------Node Creation Helper---------------------- | |
| 58 | |
| 59 Node* BeginRegion(Node* effect = nullptr) { | |
| 60 if (!effect) { | |
| 61 effect = effect_; | |
| 62 } | |
| 63 | |
| 64 return effect_ = graph()->NewNode(common()->BeginRegion(), effect); | |
| 65 } | |
| 66 | |
| 67 Node* FinishRegion(Node* value, Node* effect = nullptr) { | |
| 68 if (!effect) { | |
| 69 effect = effect_; | |
| 70 } | |
| 71 return effect_ = graph()->NewNode(common()->FinishRegion(), value, effect); | |
| 72 } | |
| 73 | |
| 74 Node* Allocate(Node* size, Node* effect = nullptr, Node* control = nullptr) { | |
| 75 if (!effect) { | |
| 76 effect = effect_; | |
| 77 } | |
| 78 if (!control) { | |
| 79 control = control_; | |
| 80 } | |
| 81 return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect, | |
| 82 control); | |
| 83 } | |
| 84 | |
| 85 Node* Constant(int num) { | |
| 86 return graph()->NewNode(common()->NumberConstant(num)); | |
| 87 } | |
| 88 | |
| 89 Node* Store(const FieldAccess& access, Node* allocation, Node* value, | |
| 90 Node* effect = nullptr, Node* control = nullptr) { | |
| 91 if (!effect) { | |
| 92 effect = effect_; | |
| 93 } | |
| 94 if (!control) { | |
| 95 control = control_; | |
| 96 } | |
| 97 return effect_ = graph()->NewNode(simplified()->StoreField(access), | |
| 98 allocation, value, effect, control); | |
| 99 } | |
| 100 | |
| 101 Node* Load(const FieldAccess& access, Node* from, Node* effect = nullptr, | |
| 102 Node* control = nullptr) { | |
| 103 if (!effect) { | |
| 104 effect = effect_; | |
| 105 } | |
| 106 if (!control) { | |
| 107 control = control_; | |
| 108 } | |
| 109 return graph()->NewNode(simplified()->LoadField(access), from, effect, | |
| 110 control); | |
| 111 } | |
| 112 | |
| 113 Node* Return(Node* value, Node* effect = nullptr, Node* control = nullptr) { | |
| 114 if (!effect) { | |
| 115 effect = effect_; | |
| 116 } | |
| 117 if (!control) { | |
| 118 control = control_; | |
| 119 } | |
| 120 return control_ = | |
| 121 graph()->NewNode(common()->Return(), value, effect, control); | |
| 122 } | |
| 123 | |
| 124 void EndGraph() { | |
| 125 for (Edge edge : graph()->end()->input_edges()) { | |
| 126 if (NodeProperties::IsControlEdge(edge)) { | |
| 127 edge.UpdateTo(control_); | |
| 128 } | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 Node* Branch() { | |
| 133 return control_ = | |
| 134 graph()->NewNode(common()->Branch(), Constant(0), control_); | |
| 135 } | |
| 136 | |
| 137 Node* IfTrue() { | |
| 138 return control_ = graph()->NewNode(common()->IfTrue(), control_); | |
| 139 } | |
| 140 | |
| 141 Node* IfFalse() { return graph()->NewNode(common()->IfFalse(), control_); } | |
| 142 | |
| 143 Node* Merge2(Node* control1, Node* control2) { | |
| 144 return control_ = graph()->NewNode(common()->Merge(2), control1, control2); | |
| 145 } | |
| 146 | |
| 147 FieldAccess AccessAtIndex(int offset) { | |
| 148 FieldAccess access = {kTaggedBase, offset, MaybeHandle<Name>(), Type::Any(), | |
| 149 kMachAnyTagged}; | |
| 150 return access; | |
| 151 } | |
| 152 | |
| 153 // ---------------------------------Assertion Helper-------------------------- | |
| 154 | |
| 155 void ExpectRepresentation(Node* node, Node* rep) { | |
| 156 EXPECT_EQ(rep, escape_objects()->representation(node, node->id())); | |
| 157 } | |
| 158 | |
| 159 void ExpectRepresentationPhi(Node* node, Node* left, Node* right) { | |
| 160 Node* rep = escape_objects()->representation(node, node->id()); | |
| 161 ASSERT_NE(nullptr, rep); | |
| 162 ASSERT_EQ(IrOpcode::kPhi, rep->opcode()); | |
| 163 EXPECT_EQ(left, NodeProperties::GetValueInput(rep, 0)); | |
| 164 EXPECT_EQ(right, NodeProperties::GetValueInput(rep, 1)); | |
| 165 } | |
| 166 | |
| 167 void ExpectVirtual(Node* node) { | |
| 168 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate || | |
| 169 node->opcode() == IrOpcode::kFinishRegion); | |
| 170 EXPECT_TRUE(escape_status()->IsVirtual(node)); | |
| 171 } | |
| 172 | |
| 173 void ExpectEscaped(Node* node) { | |
| 174 EXPECT_TRUE(node->opcode() == IrOpcode::kAllocate || | |
| 175 node->opcode() == IrOpcode::kFinishRegion); | |
| 176 EXPECT_TRUE(escape_status()->IsEscaped(node)); | |
| 177 } | |
| 178 | |
| 179 SimplifiedOperatorBuilder* simplified() { return &simplified_; } | |
| 180 | |
| 181 Node* effect() { return effect_; } | |
| 182 | |
| 183 private: | |
| 184 SimplifiedOperatorBuilder simplified_; | |
| 185 JSGraph jsgraph_; | |
| 186 EscapeStatusAnalysis* escape_status_; | |
| 187 EscapeObjectAnalysis* escape_objects_; | |
| 188 | |
| 189 Node* effect_; | |
| 190 Node* control_; | |
| 191 }; | |
| 192 | |
| 193 | |
| 194 // ----------------------------------------------------------------------------- | |
| 195 // Test cases. | |
| 196 | |
| 197 | |
| 198 TEST_F(EscapeAnalysisTest, StraightNonEscape) { | |
| 199 Node* object1 = Constant(1); | |
| 200 BeginRegion(); | |
| 201 Node* allocation = Allocate(Constant(8)); | |
| 202 Store(AccessAtIndex(0), allocation, object1); | |
| 203 Node* finish = FinishRegion(allocation); | |
| 204 Node* load = Load(AccessAtIndex(0), finish); | |
| 205 Node* result = Return(load); | |
| 206 EndGraph(); | |
| 207 Analysis(); | |
| 208 | |
| 209 ExpectVirtual(allocation); | |
| 210 ExpectRepresentation(load, object1); | |
| 211 | |
| 212 Transformation(); | |
| 213 | |
| 214 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | |
| 215 } | |
| 216 | |
| 217 | |
| 218 TEST_F(EscapeAnalysisTest, StraightEscape) { | |
| 219 Node* object1 = Constant(1); | |
| 220 BeginRegion(); | |
| 221 Node* allocation = Allocate(Constant(8)); | |
| 222 Store(AccessAtIndex(0), allocation, object1); | |
| 223 Node* finish = FinishRegion(allocation); | |
| 224 Node* load = Load(AccessAtIndex(0), finish); | |
| 225 Node* result = Return(allocation); | |
| 226 EndGraph(); | |
| 227 Analysis(); | |
| 228 | |
| 229 ExpectEscaped(allocation); | |
| 230 ExpectRepresentation(load, object1); | |
| 231 | |
| 232 Transformation(); | |
| 233 | |
| 234 ASSERT_EQ(allocation, NodeProperties::GetValueInput(result, 0)); | |
| 235 } | |
| 236 | |
| 237 | |
| 238 TEST_F(EscapeAnalysisTest, BranchNonEscape) { | |
| 239 Node* object1 = Constant(1); | |
| 240 Node* object2 = Constant(2); | |
| 241 BeginRegion(); | |
| 242 Node* allocation = Allocate(Constant(8)); | |
| 243 Store(AccessAtIndex(0), allocation, object1); | |
| 244 Node* finish = FinishRegion(allocation); | |
| 245 Branch(); | |
| 246 Node* ifFalse = IfFalse(); | |
| 247 Node* ifTrue = IfTrue(); | |
| 248 Node* effect1 = Store(AccessAtIndex(0), allocation, object1, finish, ifFalse); | |
| 249 Node* effect2 = Store(AccessAtIndex(0), allocation, object2, finish, ifTrue); | |
| 250 Node* merge = Merge2(ifFalse, ifTrue); | |
| 251 Node* phi = graph()->NewNode(common()->EffectPhi(2), effect1, effect2, merge); | |
| 252 Node* load = Load(AccessAtIndex(0), finish, phi, merge); | |
| 253 Node* result = Return(load, phi); | |
| 254 EndGraph(); | |
| 255 Analysis(); | |
| 256 | |
| 257 ExpectVirtual(allocation); | |
| 258 ExpectRepresentationPhi(load, object1, object2); | |
| 259 Node* replacement_phi = escape_objects()->representation(load, load->id()); | |
| 260 | |
| 261 Transformation(); | |
| 262 | |
| 263 ASSERT_EQ(replacement_phi, NodeProperties::GetValueInput(result, 0)); | |
| 264 } | |
| 265 | |
| 266 | |
| 267 TEST_F(EscapeAnalysisTest, DanglingLoadOrder) { | |
| 268 Node* object1 = Constant(1); | |
| 269 Node* object2 = Constant(2); | |
| 270 Node* allocation = Allocate(Constant(8)); | |
| 271 Node* store1 = Store(AccessAtIndex(0), allocation, object1); | |
| 272 Node* load1 = Load(AccessAtIndex(0), allocation); | |
| 273 Store(AccessAtIndex(0), allocation, object2); | |
| 274 Node* load2 = Load(AccessAtIndex(0), allocation, store1); | |
| 275 Node* result = Return(load2); | |
| 276 EndGraph(); | |
| 277 | |
| 278 Analysis(); | |
| 279 | |
| 280 ExpectVirtual(allocation); | |
| 281 ExpectRepresentation(load1, object1); | |
| 282 ExpectRepresentation(load2, object1); | |
| 283 | |
| 284 Transformation(); | |
| 285 | |
| 286 ASSERT_EQ(object1, NodeProperties::GetValueInput(result, 0)); | |
| 287 } | |
| 288 | |
| 289 } // namespace compiler | |
| 290 } // namespace internal | |
| 291 } // namespace v8 | |
| OLD | NEW |