| 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 |