OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler.h" | 5 #include "src/compiler.h" |
6 | 6 |
7 #include "src/compiler/access-builder.h" | 7 #include "src/compiler/access-builder.h" |
8 #include "src/compiler/js-graph.h" | 8 #include "src/compiler/js-graph.h" |
9 #include "src/compiler/js-operator.h" | 9 #include "src/compiler/js-operator.h" |
10 #include "src/compiler/js-type-feedback.h" | 10 #include "src/compiler/js-type-feedback.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 | 27 |
28 class JSTypeFeedbackTest : public TypedGraphTest { | 28 class JSTypeFeedbackTest : public TypedGraphTest { |
29 public: | 29 public: |
30 JSTypeFeedbackTest() | 30 JSTypeFeedbackTest() |
31 : TypedGraphTest(3), | 31 : TypedGraphTest(3), |
32 javascript_(zone()), | 32 javascript_(zone()), |
33 dependencies_(isolate(), zone()) {} | 33 dependencies_(isolate(), zone()) {} |
34 ~JSTypeFeedbackTest() override { dependencies_.Rollback(); } | 34 ~JSTypeFeedbackTest() override { dependencies_.Rollback(); } |
35 | 35 |
36 protected: | 36 protected: |
37 Reduction Reduce(Node* node) { | 37 Reduction Reduce(Node* node, |
| 38 JSTypeFeedbackSpecializer::DeoptimizationMode mode) { |
38 Handle<GlobalObject> global_object( | 39 Handle<GlobalObject> global_object( |
39 isolate()->native_context()->global_object(), isolate()); | 40 isolate()->native_context()->global_object(), isolate()); |
40 | 41 |
41 MachineOperatorBuilder machine(zone()); | 42 MachineOperatorBuilder machine(zone()); |
42 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); | 43 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); |
43 JSTypeFeedbackTable table(zone()); | 44 JSTypeFeedbackTable table(zone()); |
44 // TODO(titzer): mock the GraphReducer here for better unit testing. | 45 // TODO(titzer): mock the GraphReducer here for better unit testing. |
45 GraphReducer graph_reducer(graph(), zone()); | 46 GraphReducer graph_reducer(graph(), zone()); |
46 JSTypeFeedbackSpecializer reducer(&graph_reducer, &jsgraph, &table, nullptr, | 47 JSTypeFeedbackSpecializer reducer(&graph_reducer, &jsgraph, &table, nullptr, |
47 global_object, &dependencies_); | 48 global_object, mode, &dependencies_); |
48 return reducer.Reduce(node); | 49 return reducer.Reduce(node); |
49 } | 50 } |
50 | 51 |
51 Node* EmptyFrameState() { | 52 Node* EmptyFrameState() { |
52 MachineOperatorBuilder machine(zone()); | 53 MachineOperatorBuilder machine(zone()); |
53 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); | 54 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine); |
54 return jsgraph.EmptyFrameState(); | 55 return jsgraph.EmptyFrameState(); |
55 } | 56 } |
56 | 57 |
57 JSOperatorBuilder* javascript() { return &javascript_; } | 58 JSOperatorBuilder* javascript() { return &javascript_; } |
58 | 59 |
59 void SetGlobalProperty(const char* string, int value) { | 60 void SetGlobalProperty(const char* string, int value) { |
60 SetGlobalProperty(string, Handle<Smi>(Smi::FromInt(value), isolate())); | 61 SetGlobalProperty(string, Handle<Smi>(Smi::FromInt(value), isolate())); |
61 } | 62 } |
62 | 63 |
63 void SetGlobalProperty(const char* string, double value) { | 64 void SetGlobalProperty(const char* string, double value) { |
64 SetGlobalProperty(string, isolate()->factory()->NewNumber(value)); | 65 SetGlobalProperty(string, isolate()->factory()->NewNumber(value)); |
65 } | 66 } |
66 | 67 |
67 void SetGlobalProperty(const char* string, Handle<Object> value) { | 68 void SetGlobalProperty(const char* string, Handle<Object> value) { |
68 Handle<JSObject> global(isolate()->context()->global_object(), isolate()); | 69 Handle<JSObject> global(isolate()->context()->global_object(), isolate()); |
69 Handle<String> name = | 70 Handle<String> name = |
70 isolate()->factory()->NewStringFromAsciiChecked(string); | 71 isolate()->factory()->NewStringFromAsciiChecked(string); |
71 MaybeHandle<Object> result = | 72 MaybeHandle<Object> result = |
72 JSReceiver::SetProperty(global, name, value, SLOPPY); | 73 JSReceiver::SetProperty(global, name, value, SLOPPY); |
73 result.Assert(); | 74 result.Assert(); |
74 } | 75 } |
75 | 76 |
76 Node* ReturnLoadNamedFromGlobal(const char* string, Node* effect, | 77 Node* ReturnLoadNamedFromGlobal( |
77 Node* control) { | 78 const char* string, Node* effect, Node* control, |
| 79 JSTypeFeedbackSpecializer::DeoptimizationMode mode) { |
78 VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), | 80 VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(), |
79 FeedbackVectorICSlot::Invalid()); | 81 FeedbackVectorICSlot::Invalid()); |
80 Node* global = Parameter(Type::GlobalObject()); | 82 Node* global = Parameter(Type::GlobalObject()); |
81 Node* context = UndefinedConstant(); | 83 Node* context = UndefinedConstant(); |
82 | 84 |
83 Unique<Name> name = Unique<Name>::CreateUninitialized( | 85 Unique<Name> name = Unique<Name>::CreateUninitialized( |
84 isolate()->factory()->NewStringFromAsciiChecked(string)); | 86 isolate()->factory()->NewStringFromAsciiChecked(string)); |
85 const Operator* op = javascript()->LoadNamed(name, feedback); | 87 const Operator* op = javascript()->LoadNamed(name, feedback); |
86 Node* load = graph()->NewNode(op, global, context); | 88 Node* load = graph()->NewNode(op, global, context); |
87 if (FLAG_turbo_deoptimization) { | 89 if (mode == JSTypeFeedbackSpecializer::kDeoptimizationEnabled) { |
88 for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); | 90 for (int i = 0; i < OperatorProperties::GetFrameStateInputCount(op); |
89 i++) { | 91 i++) { |
90 load->AppendInput(zone(), EmptyFrameState()); | 92 load->AppendInput(zone(), EmptyFrameState()); |
91 } | 93 } |
92 } | 94 } |
93 load->AppendInput(zone(), effect); | 95 load->AppendInput(zone(), effect); |
94 load->AppendInput(zone(), control); | 96 load->AppendInput(zone(), control); |
95 Node* if_success = graph()->NewNode(common()->IfSuccess(), load); | 97 Node* if_success = graph()->NewNode(common()->IfSuccess(), load); |
96 return graph()->NewNode(common()->Return(), load, load, if_success); | 98 return graph()->NewNode(common()->Return(), load, load, if_success); |
97 } | 99 } |
98 | 100 |
99 CompilationDependencies* dependencies() { return &dependencies_; } | 101 CompilationDependencies* dependencies() { return &dependencies_; } |
100 | 102 |
101 private: | 103 private: |
102 JSOperatorBuilder javascript_; | 104 JSOperatorBuilder javascript_; |
103 CompilationDependencies dependencies_; | 105 CompilationDependencies dependencies_; |
104 }; | 106 }; |
105 | 107 |
106 #define WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION \ | 108 |
107 for (int i = FLAG_turbo_deoptimization = 0; i < 2; \ | 109 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstSmi) { |
108 FLAG_turbo_deoptimization = ++i) | 110 const int kValue = 111; |
109 | 111 const char* kName = "banana"; |
110 | 112 SetGlobalProperty(kName, kValue); |
111 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConst_smi) { | 113 |
112 const int const_value = 111; | 114 Node* ret = ReturnLoadNamedFromGlobal( |
113 const char* property_name = "banana"; | 115 kName, graph()->start(), graph()->start(), |
114 SetGlobalProperty(property_name, const_value); | 116 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
115 | 117 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
116 WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { | 118 |
117 Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), | 119 Reduction r = Reduce(ret->InputAt(0), |
118 graph()->start()); | 120 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
119 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); | 121 EXPECT_FALSE(r.Changed()); |
120 | 122 EXPECT_TRUE(dependencies()->IsEmpty()); |
121 Reduction r = Reduce(ret->InputAt(0)); | 123 } |
122 | 124 |
123 if (FLAG_turbo_deoptimization) { | 125 |
124 // Check LoadNamed(global) => HeapConstant[const_value] | 126 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstSmiWithDeoptimization) { |
125 ASSERT_TRUE(r.Changed()); | 127 const int kValue = 111; |
126 EXPECT_THAT(r.replacement(), IsNumberConstant(const_value)); | 128 const char* kName = "banana"; |
127 | 129 SetGlobalProperty(kName, kValue); |
128 EXPECT_THAT(ret, IsReturn(IsNumberConstant(const_value), graph()->start(), | 130 |
129 graph()->start())); | 131 Node* ret = ReturnLoadNamedFromGlobal( |
130 EXPECT_THAT(graph()->end(), IsEnd(ret)); | 132 kName, graph()->start(), graph()->start(), |
131 | 133 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
132 EXPECT_FALSE(dependencies()->IsEmpty()); | 134 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
133 dependencies()->Rollback(); | 135 |
134 } else { | 136 Reduction r = Reduce(ret->InputAt(0), |
135 ASSERT_FALSE(r.Changed()); | 137 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
136 EXPECT_TRUE(dependencies()->IsEmpty()); | 138 |
137 } | 139 // Check LoadNamed(global) => HeapConstant[kValue] |
138 } | 140 ASSERT_TRUE(r.Changed()); |
139 } | 141 EXPECT_THAT(r.replacement(), IsNumberConstant(kValue)); |
140 | 142 |
141 | 143 EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), graph()->start(), |
142 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConst_derble) { | 144 graph()->start())); |
143 const double const_value = -11.25; | 145 EXPECT_THAT(graph()->end(), IsEnd(ret)); |
144 const char* property_name = "kiwi"; | 146 |
145 SetGlobalProperty(property_name, const_value); | 147 EXPECT_FALSE(dependencies()->IsEmpty()); |
146 | 148 dependencies()->Rollback(); |
147 WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { | 149 } |
148 Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), | 150 |
149 graph()->start()); | 151 |
150 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); | 152 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstNumber) { |
151 | 153 const double kValue = -11.25; |
152 Reduction r = Reduce(ret->InputAt(0)); | 154 const char* kName = "kiwi"; |
153 | 155 SetGlobalProperty(kName, kValue); |
154 if (FLAG_turbo_deoptimization) { | 156 |
155 // Check LoadNamed(global) => HeapConstant[const_value] | 157 Node* ret = ReturnLoadNamedFromGlobal( |
156 ASSERT_TRUE(r.Changed()); | 158 kName, graph()->start(), graph()->start(), |
157 EXPECT_THAT(r.replacement(), IsNumberConstant(const_value)); | 159 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
158 | 160 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
159 EXPECT_THAT(ret, IsReturn(IsNumberConstant(const_value), graph()->start(), | 161 |
160 graph()->start())); | 162 Reduction r = Reduce(ret->InputAt(0), |
161 EXPECT_THAT(graph()->end(), IsEnd(ret)); | 163 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
162 | 164 |
163 EXPECT_FALSE(dependencies()->IsEmpty()); | 165 EXPECT_FALSE(r.Changed()); |
164 } else { | 166 EXPECT_TRUE(dependencies()->IsEmpty()); |
165 ASSERT_FALSE(r.Changed()); | 167 } |
166 EXPECT_TRUE(dependencies()->IsEmpty()); | 168 |
167 } | 169 |
168 } | 170 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstNumberWithDeoptimization) { |
169 } | 171 const double kValue = -11.25; |
170 | 172 const char* kName = "kiwi"; |
171 | 173 SetGlobalProperty(kName, kValue); |
172 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConst_string) { | 174 |
173 Unique<HeapObject> const_value = Unique<HeapObject>::CreateImmovable( | 175 Node* ret = ReturnLoadNamedFromGlobal( |
| 176 kName, graph()->start(), graph()->start(), |
| 177 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
| 178 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
| 179 |
| 180 Reduction r = Reduce(ret->InputAt(0), |
| 181 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
| 182 |
| 183 // Check LoadNamed(global) => HeapConstant[kValue] |
| 184 ASSERT_TRUE(r.Changed()); |
| 185 EXPECT_THAT(r.replacement(), IsNumberConstant(kValue)); |
| 186 |
| 187 EXPECT_THAT(ret, IsReturn(IsNumberConstant(kValue), graph()->start(), |
| 188 graph()->start())); |
| 189 EXPECT_THAT(graph()->end(), IsEnd(ret)); |
| 190 |
| 191 EXPECT_FALSE(dependencies()->IsEmpty()); |
| 192 } |
| 193 |
| 194 |
| 195 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstString) { |
| 196 Unique<HeapObject> kValue = Unique<HeapObject>::CreateImmovable( |
174 isolate()->factory()->undefined_string()); | 197 isolate()->factory()->undefined_string()); |
175 const char* property_name = "mango"; | 198 const char* kName = "mango"; |
176 SetGlobalProperty(property_name, const_value.handle()); | 199 SetGlobalProperty(kName, kValue.handle()); |
177 | 200 |
178 WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { | 201 Node* ret = ReturnLoadNamedFromGlobal( |
179 Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), | 202 kName, graph()->start(), graph()->start(), |
180 graph()->start()); | 203 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
181 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); | 204 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
182 | 205 |
183 Reduction r = Reduce(ret->InputAt(0)); | 206 Reduction r = Reduce(ret->InputAt(0), |
184 | 207 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
185 if (FLAG_turbo_deoptimization) { | 208 ASSERT_FALSE(r.Changed()); |
186 // Check LoadNamed(global) => HeapConstant[const_value] | 209 EXPECT_TRUE(dependencies()->IsEmpty()); |
187 ASSERT_TRUE(r.Changed()); | 210 } |
188 EXPECT_THAT(r.replacement(), IsHeapConstant(const_value)); | 211 |
189 | 212 |
190 EXPECT_THAT(ret, IsReturn(IsHeapConstant(const_value), graph()->start(), | 213 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalConstStringWithDeoptimization) { |
191 graph()->start())); | 214 Unique<HeapObject> kValue = Unique<HeapObject>::CreateImmovable( |
192 EXPECT_THAT(graph()->end(), IsEnd(ret)); | 215 isolate()->factory()->undefined_string()); |
193 | 216 const char* kName = "mango"; |
194 EXPECT_FALSE(dependencies()->IsEmpty()); | 217 SetGlobalProperty(kName, kValue.handle()); |
195 dependencies()->Rollback(); | 218 |
196 } else { | 219 Node* ret = ReturnLoadNamedFromGlobal( |
197 ASSERT_FALSE(r.Changed()); | 220 kName, graph()->start(), graph()->start(), |
198 EXPECT_TRUE(dependencies()->IsEmpty()); | 221 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
199 } | 222 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
200 } | 223 |
201 } | 224 Reduction r = Reduce(ret->InputAt(0), |
202 | 225 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
203 | 226 |
204 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCell_smi) { | 227 // Check LoadNamed(global) => HeapConstant[kValue] |
205 const char* property_name = "melon"; | 228 ASSERT_TRUE(r.Changed()); |
206 SetGlobalProperty(property_name, 123); | 229 EXPECT_THAT(r.replacement(), IsHeapConstant(kValue)); |
207 SetGlobalProperty(property_name, 124); | 230 |
208 | 231 EXPECT_THAT(ret, IsReturn(IsHeapConstant(kValue), graph()->start(), |
209 WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { | 232 graph()->start())); |
210 Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), | 233 EXPECT_THAT(graph()->end(), IsEnd(ret)); |
211 graph()->start()); | 234 |
212 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); | 235 EXPECT_FALSE(dependencies()->IsEmpty()); |
213 | 236 dependencies()->Rollback(); |
214 Reduction r = Reduce(ret->InputAt(0)); | 237 } |
215 | 238 |
216 if (FLAG_turbo_deoptimization) { | 239 |
217 // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) | 240 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellSmi) { |
218 ASSERT_TRUE(r.Changed()); | 241 const char* kName = "melon"; |
219 FieldAccess access = AccessBuilder::ForPropertyCellValue(); | 242 SetGlobalProperty(kName, 123); |
220 Capture<Node*> cell_capture; | 243 SetGlobalProperty(kName, 124); |
221 Matcher<Node*> load_field_match = IsLoadField( | 244 |
222 access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); | 245 Node* ret = ReturnLoadNamedFromGlobal( |
223 EXPECT_THAT(r.replacement(), load_field_match); | 246 kName, graph()->start(), graph()->start(), |
224 | 247 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
225 HeapObjectMatcher<PropertyCell> cell(cell_capture.value()); | 248 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
226 EXPECT_TRUE(cell.HasValue()); | 249 |
227 EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); | 250 Reduction r = Reduce(ret->InputAt(0), |
228 | 251 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
229 EXPECT_THAT( | 252 ASSERT_FALSE(r.Changed()); |
230 ret, IsReturn(load_field_match, load_field_match, graph()->start())); | 253 EXPECT_TRUE(dependencies()->IsEmpty()); |
231 EXPECT_THAT(graph()->end(), IsEnd(ret)); | 254 } |
232 | 255 |
233 EXPECT_FALSE(dependencies()->IsEmpty()); | 256 |
234 dependencies()->Rollback(); | 257 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellSmiWithDeoptimization) { |
235 } else { | 258 const char* kName = "melon"; |
236 ASSERT_FALSE(r.Changed()); | 259 SetGlobalProperty(kName, 123); |
237 EXPECT_TRUE(dependencies()->IsEmpty()); | 260 SetGlobalProperty(kName, 124); |
238 } | 261 |
239 } | 262 Node* ret = ReturnLoadNamedFromGlobal( |
240 } | 263 kName, graph()->start(), graph()->start(), |
241 | 264 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
242 | 265 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
243 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCell_string) { | 266 |
244 const char* property_name = "pineapple"; | 267 Reduction r = Reduce(ret->InputAt(0), |
245 SetGlobalProperty(property_name, isolate()->factory()->undefined_string()); | 268 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
246 SetGlobalProperty(property_name, isolate()->factory()->undefined_value()); | 269 |
247 | 270 // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) |
248 WITH_AND_WITHOUT_TURBO_DEOPTIMIZATION { | 271 ASSERT_TRUE(r.Changed()); |
249 Node* ret = ReturnLoadNamedFromGlobal(property_name, graph()->start(), | 272 FieldAccess access = AccessBuilder::ForPropertyCellValue(); |
250 graph()->start()); | 273 Capture<Node*> cell_capture; |
251 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); | 274 Matcher<Node*> load_field_match = IsLoadField( |
252 | 275 access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); |
253 Reduction r = Reduce(ret->InputAt(0)); | 276 EXPECT_THAT(r.replacement(), load_field_match); |
254 | 277 |
255 if (FLAG_turbo_deoptimization) { | 278 HeapObjectMatcher<PropertyCell> cell(cell_capture.value()); |
256 // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) | 279 EXPECT_TRUE(cell.HasValue()); |
257 ASSERT_TRUE(r.Changed()); | 280 EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); |
258 FieldAccess access = AccessBuilder::ForPropertyCellValue(); | 281 |
259 Capture<Node*> cell_capture; | 282 EXPECT_THAT(ret, |
260 Matcher<Node*> load_field_match = IsLoadField( | 283 IsReturn(load_field_match, load_field_match, graph()->start())); |
261 access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); | 284 EXPECT_THAT(graph()->end(), IsEnd(ret)); |
262 EXPECT_THAT(r.replacement(), load_field_match); | 285 |
263 | 286 EXPECT_FALSE(dependencies()->IsEmpty()); |
264 HeapObjectMatcher<PropertyCell> cell(cell_capture.value()); | 287 dependencies()->Rollback(); |
265 EXPECT_TRUE(cell.HasValue()); | 288 } |
266 EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); | 289 |
267 | 290 |
268 EXPECT_THAT( | 291 TEST_F(JSTypeFeedbackTest, JSLoadNamedGlobalPropertyCellString) { |
269 ret, IsReturn(load_field_match, load_field_match, graph()->start())); | 292 const char* kName = "pineapple"; |
270 EXPECT_THAT(graph()->end(), IsEnd(ret)); | 293 SetGlobalProperty(kName, isolate()->factory()->undefined_string()); |
271 | 294 SetGlobalProperty(kName, isolate()->factory()->undefined_value()); |
272 EXPECT_FALSE(dependencies()->IsEmpty()); | 295 |
273 dependencies()->Rollback(); | 296 Node* ret = ReturnLoadNamedFromGlobal( |
274 } else { | 297 kName, graph()->start(), graph()->start(), |
275 ASSERT_FALSE(r.Changed()); | 298 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
276 EXPECT_TRUE(dependencies()->IsEmpty()); | 299 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
277 } | 300 |
278 } | 301 Reduction r = Reduce(ret->InputAt(0), |
279 } | 302 JSTypeFeedbackSpecializer::kDeoptimizationDisabled); |
280 } | 303 ASSERT_FALSE(r.Changed()); |
281 } | 304 EXPECT_TRUE(dependencies()->IsEmpty()); |
282 } | 305 } |
| 306 |
| 307 |
| 308 TEST_F(JSTypeFeedbackTest, |
| 309 JSLoadNamedGlobalPropertyCellStringWithDeoptimization) { |
| 310 const char* kName = "pineapple"; |
| 311 SetGlobalProperty(kName, isolate()->factory()->undefined_string()); |
| 312 SetGlobalProperty(kName, isolate()->factory()->undefined_value()); |
| 313 |
| 314 Node* ret = ReturnLoadNamedFromGlobal( |
| 315 kName, graph()->start(), graph()->start(), |
| 316 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
| 317 graph()->SetEnd(graph()->NewNode(common()->End(), ret)); |
| 318 |
| 319 Reduction r = Reduce(ret->InputAt(0), |
| 320 JSTypeFeedbackSpecializer::kDeoptimizationEnabled); |
| 321 |
| 322 // Check LoadNamed(global) => LoadField[PropertyCell::value](cell) |
| 323 ASSERT_TRUE(r.Changed()); |
| 324 FieldAccess access = AccessBuilder::ForPropertyCellValue(); |
| 325 Capture<Node*> cell_capture; |
| 326 Matcher<Node*> load_field_match = IsLoadField( |
| 327 access, CaptureEq(&cell_capture), graph()->start(), graph()->start()); |
| 328 EXPECT_THAT(r.replacement(), load_field_match); |
| 329 |
| 330 HeapObjectMatcher<PropertyCell> cell(cell_capture.value()); |
| 331 EXPECT_TRUE(cell.HasValue()); |
| 332 EXPECT_TRUE(cell.Value().handle()->IsPropertyCell()); |
| 333 |
| 334 EXPECT_THAT(ret, |
| 335 IsReturn(load_field_match, load_field_match, graph()->start())); |
| 336 EXPECT_THAT(graph()->end(), IsEnd(ret)); |
| 337 |
| 338 EXPECT_FALSE(dependencies()->IsEmpty()); |
| 339 dependencies()->Rollback(); |
| 340 } |
| 341 |
| 342 } // namespace compiler |
| 343 } // namespace internal |
| 344 } // namespace v8 |
OLD | NEW |