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/js-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 // The final states for every polymorphic branch. We join them with | 105 // The final states for every polymorphic branch. We join them with |
106 // Merge++Phi+EffectPhi at the bottom. | 106 // Merge++Phi+EffectPhi at the bottom. |
107 ZoneVector<Node*> values(zone()); | 107 ZoneVector<Node*> values(zone()); |
108 ZoneVector<Node*> effects(zone()); | 108 ZoneVector<Node*> effects(zone()); |
109 ZoneVector<Node*> controls(zone()); | 109 ZoneVector<Node*> controls(zone()); |
110 | 110 |
111 // Ensure that {index} matches the specified {name} (if {index} is given). | 111 // Ensure that {index} matches the specified {name} (if {index} is given). |
112 if (index != nullptr) { | 112 if (index != nullptr) { |
113 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), | 113 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
114 index, jsgraph()->HeapConstant(name)); | 114 index, jsgraph()->HeapConstant(name)); |
115 control = graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 115 control = effect = graph()->NewNode(common()->DeoptimizeUnless(), check, |
116 effect, control); | 116 frame_state, effect, control); |
117 } | 117 } |
118 | 118 |
119 // Check if {receiver} may be a number. | 119 // Check if {receiver} may be a number. |
120 bool receiverissmi_possible = false; | 120 bool receiverissmi_possible = false; |
121 for (PropertyAccessInfo const& access_info : access_infos) { | 121 for (PropertyAccessInfo const& access_info : access_infos) { |
122 if (access_info.receiver_type()->Is(Type::Number())) { | 122 if (access_info.receiver_type()->Is(Type::Number())) { |
123 receiverissmi_possible = true; | 123 receiverissmi_possible = true; |
124 break; | 124 break; |
125 } | 125 } |
126 } | 126 } |
127 | 127 |
128 // Ensure that {receiver} is a heap object. | 128 // Ensure that {receiver} is a heap object. |
129 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 129 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
130 Node* receiverissmi_control = nullptr; | 130 Node* receiverissmi_control = nullptr; |
131 Node* receiverissmi_effect = effect; | 131 Node* receiverissmi_effect = effect; |
132 if (receiverissmi_possible) { | 132 if (receiverissmi_possible) { |
133 Node* branch = graph()->NewNode(common()->Branch(), check, control); | 133 Node* branch = graph()->NewNode(common()->Branch(), check, control); |
134 control = graph()->NewNode(common()->IfFalse(), branch); | 134 control = graph()->NewNode(common()->IfFalse(), branch); |
135 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); | 135 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
136 receiverissmi_effect = effect; | 136 receiverissmi_effect = effect; |
137 } else { | 137 } else { |
138 control = graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, | 138 control = effect = graph()->NewNode(common()->DeoptimizeIf(), check, |
139 effect, control); | 139 frame_state, effect, control); |
140 } | 140 } |
141 | 141 |
142 // Load the {receiver} map. The resulting effect is the dominating effect for | 142 // Load the {receiver} map. The resulting effect is the dominating effect for |
143 // all (polymorphic) branches. | 143 // all (polymorphic) branches. |
144 Node* receiver_map = effect = | 144 Node* receiver_map = effect = |
145 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 145 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
146 receiver, effect, control); | 146 receiver, effect, control); |
147 | 147 |
148 // Generate code for the various different property access patterns. | 148 // Generate code for the various different property access patterns. |
149 Node* fallthrough_control = control; | 149 Node* fallthrough_control = control; |
150 for (size_t j = 0; j < access_infos.size(); ++j) { | 150 for (size_t j = 0; j < access_infos.size(); ++j) { |
151 PropertyAccessInfo const& access_info = access_infos[j]; | 151 PropertyAccessInfo const& access_info = access_infos[j]; |
152 Node* this_value = value; | 152 Node* this_value = value; |
153 Node* this_receiver = receiver; | 153 Node* this_receiver = receiver; |
154 Node* this_effect = effect; | 154 Node* this_effect = effect; |
155 Node* this_control; | 155 Node* this_control; |
156 | 156 |
157 // Perform map check on {receiver}. | 157 // Perform map check on {receiver}. |
158 Type* receiver_type = access_info.receiver_type(); | 158 Type* receiver_type = access_info.receiver_type(); |
159 if (receiver_type->Is(Type::String())) { | 159 if (receiver_type->Is(Type::String())) { |
160 Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver); | 160 Node* check = graph()->NewNode(simplified()->ObjectIsString(), receiver); |
161 if (j == access_infos.size() - 1) { | 161 if (j == access_infos.size() - 1) { |
162 this_control = | 162 this_control = this_effect = |
163 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 163 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
164 this_effect, fallthrough_control); | 164 this_effect, fallthrough_control); |
165 fallthrough_control = nullptr; | 165 fallthrough_control = nullptr; |
166 } else { | 166 } else { |
167 Node* branch = | 167 Node* branch = |
168 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 168 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
169 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 169 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
170 this_control = graph()->NewNode(common()->IfTrue(), branch); | 170 this_control = graph()->NewNode(common()->IfTrue(), branch); |
171 } | 171 } |
172 } else { | 172 } else { |
173 // Emit a (sequence of) map checks for other {receiver}s. | 173 // Emit a (sequence of) map checks for other {receiver}s. |
174 ZoneVector<Node*> this_controls(zone()); | 174 ZoneVector<Node*> this_controls(zone()); |
175 ZoneVector<Node*> this_effects(zone()); | 175 ZoneVector<Node*> this_effects(zone()); |
176 int num_classes = access_info.receiver_type()->NumClasses(); | 176 int num_classes = access_info.receiver_type()->NumClasses(); |
177 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | 177 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
178 i.Advance()) { | 178 i.Advance()) { |
179 DCHECK_LT(0, num_classes); | 179 DCHECK_LT(0, num_classes); |
180 Handle<Map> map = i.Current(); | 180 Handle<Map> map = i.Current(); |
181 Node* check = | 181 Node* check = |
182 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), | 182 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), |
183 receiver_map, jsgraph()->Constant(map)); | 183 receiver_map, jsgraph()->Constant(map)); |
184 if (--num_classes == 0 && j == access_infos.size() - 1) { | 184 if (--num_classes == 0 && j == access_infos.size() - 1) { |
185 this_controls.push_back( | 185 Node* deoptimize = |
186 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 186 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
187 this_effect, fallthrough_control)); | 187 this_effect, fallthrough_control); |
188 this_effects.push_back(this_effect); | 188 this_controls.push_back(deoptimize); |
| 189 this_effects.push_back(deoptimize); |
189 fallthrough_control = nullptr; | 190 fallthrough_control = nullptr; |
190 } else { | 191 } else { |
191 Node* branch = | 192 Node* branch = |
192 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 193 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
193 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 194 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
194 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 195 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
195 this_effects.push_back(this_effect); | 196 this_effects.push_back(this_effect); |
196 } | 197 } |
197 } | 198 } |
198 | 199 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 | 231 |
231 // Generate the actual property access. | 232 // Generate the actual property access. |
232 if (access_info.IsNotFound()) { | 233 if (access_info.IsNotFound()) { |
233 DCHECK_EQ(AccessMode::kLoad, access_mode); | 234 DCHECK_EQ(AccessMode::kLoad, access_mode); |
234 this_value = jsgraph()->UndefinedConstant(); | 235 this_value = jsgraph()->UndefinedConstant(); |
235 } else if (access_info.IsDataConstant()) { | 236 } else if (access_info.IsDataConstant()) { |
236 this_value = jsgraph()->Constant(access_info.constant()); | 237 this_value = jsgraph()->Constant(access_info.constant()); |
237 if (access_mode == AccessMode::kStore) { | 238 if (access_mode == AccessMode::kStore) { |
238 Node* check = graph()->NewNode( | 239 Node* check = graph()->NewNode( |
239 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); | 240 simplified()->ReferenceEqual(Type::Tagged()), value, this_value); |
240 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 241 this_control = this_effect = |
241 frame_state, this_effect, this_control); | 242 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 243 this_effect, this_control); |
242 } | 244 } |
243 } else { | 245 } else { |
244 DCHECK(access_info.IsDataField()); | 246 DCHECK(access_info.IsDataField()); |
245 FieldIndex const field_index = access_info.field_index(); | 247 FieldIndex const field_index = access_info.field_index(); |
246 FieldCheck const field_check = access_info.field_check(); | 248 FieldCheck const field_check = access_info.field_check(); |
247 Type* const field_type = access_info.field_type(); | 249 Type* const field_type = access_info.field_type(); |
248 switch (field_check) { | 250 switch (field_check) { |
249 case FieldCheck::kNone: | 251 case FieldCheck::kNone: |
250 break; | 252 break; |
251 case FieldCheck::kJSArrayBufferViewBufferNotNeutered: { | 253 case FieldCheck::kJSArrayBufferViewBufferNotNeutered: { |
252 Node* this_buffer = this_effect = | 254 Node* this_buffer = this_effect = |
253 graph()->NewNode(simplified()->LoadField( | 255 graph()->NewNode(simplified()->LoadField( |
254 AccessBuilder::ForJSArrayBufferViewBuffer()), | 256 AccessBuilder::ForJSArrayBufferViewBuffer()), |
255 this_receiver, this_effect, this_control); | 257 this_receiver, this_effect, this_control); |
256 Node* this_buffer_bit_field = this_effect = | 258 Node* this_buffer_bit_field = this_effect = |
257 graph()->NewNode(simplified()->LoadField( | 259 graph()->NewNode(simplified()->LoadField( |
258 AccessBuilder::ForJSArrayBufferBitField()), | 260 AccessBuilder::ForJSArrayBufferBitField()), |
259 this_buffer, this_effect, this_control); | 261 this_buffer, this_effect, this_control); |
260 Node* check = graph()->NewNode( | 262 Node* check = graph()->NewNode( |
261 machine()->Word32Equal(), | 263 machine()->Word32Equal(), |
262 graph()->NewNode(machine()->Word32And(), this_buffer_bit_field, | 264 graph()->NewNode(machine()->Word32And(), this_buffer_bit_field, |
263 jsgraph()->Int32Constant( | 265 jsgraph()->Int32Constant( |
264 1 << JSArrayBuffer::WasNeutered::kShift)), | 266 1 << JSArrayBuffer::WasNeutered::kShift)), |
265 jsgraph()->Int32Constant(0)); | 267 jsgraph()->Int32Constant(0)); |
266 this_control = | 268 this_control = this_effect = |
267 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 269 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
268 this_effect, this_control); | 270 this_effect, this_control); |
269 break; | 271 break; |
270 } | 272 } |
271 } | 273 } |
272 if (access_mode == AccessMode::kLoad && | 274 if (access_mode == AccessMode::kLoad && |
273 access_info.holder().ToHandle(&holder)) { | 275 access_info.holder().ToHandle(&holder)) { |
274 this_receiver = jsgraph()->Constant(holder); | 276 this_receiver = jsgraph()->Constant(holder); |
275 } | 277 } |
276 Node* this_storage = this_receiver; | 278 Node* this_storage = this_receiver; |
(...skipping 18 matching lines...) Expand all Loading... |
295 field_access.machine_type = MachineType::Float64(); | 297 field_access.machine_type = MachineType::Float64(); |
296 } | 298 } |
297 this_value = this_effect = | 299 this_value = this_effect = |
298 graph()->NewNode(simplified()->LoadField(field_access), | 300 graph()->NewNode(simplified()->LoadField(field_access), |
299 this_storage, this_effect, this_control); | 301 this_storage, this_effect, this_control); |
300 } else { | 302 } else { |
301 DCHECK_EQ(AccessMode::kStore, access_mode); | 303 DCHECK_EQ(AccessMode::kStore, access_mode); |
302 if (field_type->Is(Type::UntaggedFloat64())) { | 304 if (field_type->Is(Type::UntaggedFloat64())) { |
303 Node* check = | 305 Node* check = |
304 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); | 306 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); |
305 this_control = | 307 this_control = this_effect = |
306 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 308 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
307 this_effect, this_control); | 309 this_effect, this_control); |
308 this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()), | 310 this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()), |
309 this_value, this_control); | 311 this_value, this_control); |
310 | 312 |
311 if (!field_index.is_inobject() || field_index.is_hidden_field() || | 313 if (!field_index.is_inobject() || field_index.is_hidden_field() || |
312 !FLAG_unbox_double_fields) { | 314 !FLAG_unbox_double_fields) { |
313 if (access_info.HasTransitionMap()) { | 315 if (access_info.HasTransitionMap()) { |
314 // Allocate a MutableHeapNumber for the new property. | 316 // Allocate a MutableHeapNumber for the new property. |
315 this_effect = | 317 this_effect = |
(...skipping 22 matching lines...) Expand all Loading... |
338 field_access.name = MaybeHandle<Name>(); | 340 field_access.name = MaybeHandle<Name>(); |
339 field_access.machine_type = MachineType::Float64(); | 341 field_access.machine_type = MachineType::Float64(); |
340 } | 342 } |
341 } else { | 343 } else { |
342 // Unboxed double field, we store directly to the field. | 344 // Unboxed double field, we store directly to the field. |
343 field_access.machine_type = MachineType::Float64(); | 345 field_access.machine_type = MachineType::Float64(); |
344 } | 346 } |
345 } else if (field_type->Is(Type::TaggedSigned())) { | 347 } else if (field_type->Is(Type::TaggedSigned())) { |
346 Node* check = | 348 Node* check = |
347 graph()->NewNode(simplified()->ObjectIsSmi(), this_value); | 349 graph()->NewNode(simplified()->ObjectIsSmi(), this_value); |
348 this_control = | 350 this_control = this_effect = |
349 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 351 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
350 this_effect, this_control); | 352 this_effect, this_control); |
351 this_value = | 353 this_value = |
352 graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi), | 354 graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi), |
353 this_value, this_control); | 355 this_value, this_control); |
354 } else if (field_type->Is(Type::TaggedPointer())) { | 356 } else if (field_type->Is(Type::TaggedPointer())) { |
355 Node* check = | 357 Node* check = |
356 graph()->NewNode(simplified()->ObjectIsSmi(), this_value); | 358 graph()->NewNode(simplified()->ObjectIsSmi(), this_value); |
357 this_control = | 359 this_control = this_effect = |
358 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, | 360 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, |
359 this_effect, this_control); | 361 this_effect, this_control); |
360 if (field_type->NumClasses() == 1) { | 362 if (field_type->NumClasses() == 1) { |
361 // Emit a map check for the value. | 363 // Emit a map check for the value. |
362 Node* this_value_map = this_effect = graph()->NewNode( | 364 Node* this_value_map = this_effect = graph()->NewNode( |
363 simplified()->LoadField(AccessBuilder::ForMap()), this_value, | 365 simplified()->LoadField(AccessBuilder::ForMap()), this_value, |
364 this_effect, this_control); | 366 this_effect, this_control); |
365 Node* check = graph()->NewNode( | 367 Node* check = graph()->NewNode( |
366 simplified()->ReferenceEqual(Type::Internal()), this_value_map, | 368 simplified()->ReferenceEqual(Type::Internal()), this_value_map, |
367 jsgraph()->Constant(field_type->Classes().Current())); | 369 jsgraph()->Constant(field_type->Classes().Current())); |
368 this_control = | 370 this_control = this_effect = |
369 graph()->NewNode(common()->DeoptimizeUnless(), check, | 371 graph()->NewNode(common()->DeoptimizeUnless(), check, |
370 frame_state, this_effect, this_control); | 372 frame_state, this_effect, this_control); |
371 } else { | 373 } else { |
372 DCHECK_EQ(0, field_type->NumClasses()); | 374 DCHECK_EQ(0, field_type->NumClasses()); |
373 } | 375 } |
374 } else { | 376 } else { |
375 DCHECK(field_type->Is(Type::Tagged())); | 377 DCHECK(field_type->Is(Type::Tagged())); |
376 } | 378 } |
377 Handle<Map> transition_map; | 379 Handle<Map> transition_map; |
378 if (access_info.transition_map().ToHandle(&transition_map)) { | 380 if (access_info.transition_map().ToHandle(&transition_map)) { |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
549 if (access_infos.empty()) return NoChange(); | 551 if (access_infos.empty()) return NoChange(); |
550 | 552 |
551 // The final states for every polymorphic branch. We join them with | 553 // The final states for every polymorphic branch. We join them with |
552 // Merge+Phi+EffectPhi at the bottom. | 554 // Merge+Phi+EffectPhi at the bottom. |
553 ZoneVector<Node*> values(zone()); | 555 ZoneVector<Node*> values(zone()); |
554 ZoneVector<Node*> effects(zone()); | 556 ZoneVector<Node*> effects(zone()); |
555 ZoneVector<Node*> controls(zone()); | 557 ZoneVector<Node*> controls(zone()); |
556 | 558 |
557 // Ensure that {receiver} is a heap object. | 559 // Ensure that {receiver} is a heap object. |
558 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 560 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
559 control = graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, | 561 control = effect = graph()->NewNode(common()->DeoptimizeIf(), check, |
560 effect, control); | 562 frame_state, effect, control); |
561 | 563 |
562 // Load the {receiver} map. The resulting effect is the dominating effect for | 564 // Load the {receiver} map. The resulting effect is the dominating effect for |
563 // all (polymorphic) branches. | 565 // all (polymorphic) branches. |
564 Node* receiver_map = effect = | 566 Node* receiver_map = effect = |
565 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 567 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
566 receiver, effect, control); | 568 receiver, effect, control); |
567 | 569 |
568 // Generate code for the various different element access patterns. | 570 // Generate code for the various different element access patterns. |
569 Node* fallthrough_control = control; | 571 Node* fallthrough_control = control; |
570 for (size_t j = 0; j < access_infos.size(); ++j) { | 572 for (size_t j = 0; j < access_infos.size(); ++j) { |
(...skipping 19 matching lines...) Expand all Loading... |
590 Node* check = | 592 Node* check = |
591 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), | 593 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), |
592 receiver_map, jsgraph()->Constant(map)); | 594 receiver_map, jsgraph()->Constant(map)); |
593 if (--num_classes == 0 && num_transitions == 0 && | 595 if (--num_classes == 0 && num_transitions == 0 && |
594 j == access_infos.size() - 1) { | 596 j == access_infos.size() - 1) { |
595 // Last map check on the fallthrough control path, do a conditional | 597 // Last map check on the fallthrough control path, do a conditional |
596 // eager deoptimization exit here. | 598 // eager deoptimization exit here. |
597 // TODO(turbofan): This is ugly as hell! We should probably introduce | 599 // TODO(turbofan): This is ugly as hell! We should probably introduce |
598 // macro-ish operators for property access that encapsulate this whole | 600 // macro-ish operators for property access that encapsulate this whole |
599 // mess. | 601 // mess. |
600 this_controls.push_back(graph()->NewNode(common()->DeoptimizeUnless(), | 602 Node* deoptimize = |
601 check, frame_state, effect, | 603 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
602 fallthrough_control)); | 604 effect, fallthrough_control); |
| 605 this_controls.push_back(deoptimize); |
| 606 this_effects.push_back(deoptimize); |
603 fallthrough_control = nullptr; | 607 fallthrough_control = nullptr; |
604 } else { | 608 } else { |
605 Node* branch = | 609 Node* branch = |
606 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 610 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
607 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 611 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
| 612 this_effects.push_back(effect); |
608 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 613 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
609 } | 614 } |
610 this_effects.push_back(effect); | |
611 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; | 615 if (!map->IsJSArrayMap()) receiver_is_jsarray = false; |
612 } | 616 } |
613 | 617 |
614 // Generate possible elements kind transitions. | 618 // Generate possible elements kind transitions. |
615 for (auto transition : access_info.transitions()) { | 619 for (auto transition : access_info.transitions()) { |
616 DCHECK_LT(0u, num_transitions); | 620 DCHECK_LT(0u, num_transitions); |
617 Handle<Map> transition_source = transition.first; | 621 Handle<Map> transition_source = transition.first; |
618 Handle<Map> transition_target = transition.second; | 622 Handle<Map> transition_target = transition.second; |
619 Node* transition_control; | 623 Node* transition_control; |
620 Node* transition_effect = effect; | 624 Node* transition_effect = effect; |
621 | 625 |
622 // Check if {receiver} has the specified {transition_source} map. | 626 // Check if {receiver} has the specified {transition_source} map. |
623 Node* check = graph()->NewNode( | 627 Node* check = graph()->NewNode( |
624 simplified()->ReferenceEqual(Type::Any()), receiver_map, | 628 simplified()->ReferenceEqual(Type::Any()), receiver_map, |
625 jsgraph()->HeapConstant(transition_source)); | 629 jsgraph()->HeapConstant(transition_source)); |
626 if (--num_transitions == 0 && j == access_infos.size() - 1) { | 630 if (--num_transitions == 0 && j == access_infos.size() - 1) { |
627 transition_control = | 631 transition_control = transition_effect = |
628 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, | 632 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
629 transition_effect, fallthrough_control); | 633 transition_effect, fallthrough_control); |
630 fallthrough_control = nullptr; | 634 fallthrough_control = nullptr; |
631 } else { | 635 } else { |
632 Node* branch = | 636 Node* branch = |
633 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 637 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
634 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 638 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
635 transition_control = graph()->NewNode(common()->IfTrue(), branch); | 639 transition_control = graph()->NewNode(common()->IfTrue(), branch); |
636 } | 640 } |
637 | 641 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 // not compatible with (monomorphic) keyed stores. | 686 // not compatible with (monomorphic) keyed stores. |
683 Handle<JSObject> holder; | 687 Handle<JSObject> holder; |
684 if (access_info.holder().ToHandle(&holder)) { | 688 if (access_info.holder().ToHandle(&holder)) { |
685 AssumePrototypesStable(receiver_type, native_context, holder); | 689 AssumePrototypesStable(receiver_type, native_context, holder); |
686 } | 690 } |
687 | 691 |
688 // Check that the {index} is actually a Number. | 692 // Check that the {index} is actually a Number. |
689 if (!NumberMatcher(this_index).HasValue()) { | 693 if (!NumberMatcher(this_index).HasValue()) { |
690 Node* check = | 694 Node* check = |
691 graph()->NewNode(simplified()->ObjectIsNumber(), this_index); | 695 graph()->NewNode(simplified()->ObjectIsNumber(), this_index); |
692 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 696 this_control = this_effect = |
693 frame_state, this_effect, this_control); | 697 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 698 this_effect, this_control); |
694 this_index = graph()->NewNode(simplified()->TypeGuard(Type::Number()), | 699 this_index = graph()->NewNode(simplified()->TypeGuard(Type::Number()), |
695 this_index, this_control); | 700 this_index, this_control); |
696 } | 701 } |
697 | 702 |
698 // Convert the {index} to an unsigned32 value and check if the result is | 703 // Convert the {index} to an unsigned32 value and check if the result is |
699 // equal to the original {index}. | 704 // equal to the original {index}. |
700 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) { | 705 if (!NumberMatcher(this_index).IsInRange(0.0, kMaxUInt32)) { |
701 Node* this_index32 = | 706 Node* this_index32 = |
702 graph()->NewNode(simplified()->NumberToUint32(), this_index); | 707 graph()->NewNode(simplified()->NumberToUint32(), this_index); |
703 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32, | 708 Node* check = graph()->NewNode(simplified()->NumberEqual(), this_index32, |
704 this_index); | 709 this_index); |
705 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 710 this_control = this_effect = |
706 frame_state, this_effect, this_control); | 711 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 712 this_effect, this_control); |
707 this_index = this_index32; | 713 this_index = this_index32; |
708 } | 714 } |
709 | 715 |
710 // TODO(bmeurer): We currently specialize based on elements kind. We should | 716 // TODO(bmeurer): We currently specialize based on elements kind. We should |
711 // also be able to properly support strings and other JSObjects here. | 717 // also be able to properly support strings and other JSObjects here. |
712 ElementsKind elements_kind = access_info.elements_kind(); | 718 ElementsKind elements_kind = access_info.elements_kind(); |
713 | 719 |
714 // Load the elements for the {receiver}. | 720 // Load the elements for the {receiver}. |
715 Node* this_elements = this_effect = graph()->NewNode( | 721 Node* this_elements = this_effect = graph()->NewNode( |
716 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), | 722 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), |
717 this_receiver, this_effect, this_control); | 723 this_receiver, this_effect, this_control); |
718 | 724 |
719 // Don't try to store to a copy-on-write backing store. | 725 // Don't try to store to a copy-on-write backing store. |
720 if (access_mode == AccessMode::kStore && | 726 if (access_mode == AccessMode::kStore && |
721 IsFastSmiOrObjectElementsKind(elements_kind)) { | 727 IsFastSmiOrObjectElementsKind(elements_kind)) { |
722 Node* this_elements_map = this_effect = | 728 Node* this_elements_map = this_effect = |
723 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 729 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
724 this_elements, this_effect, this_control); | 730 this_elements, this_effect, this_control); |
725 Node* check = graph()->NewNode( | 731 Node* check = graph()->NewNode( |
726 simplified()->ReferenceEqual(Type::Any()), this_elements_map, | 732 simplified()->ReferenceEqual(Type::Any()), this_elements_map, |
727 jsgraph()->HeapConstant(factory()->fixed_array_map())); | 733 jsgraph()->HeapConstant(factory()->fixed_array_map())); |
728 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 734 this_control = this_effect = |
729 frame_state, this_effect, this_control); | 735 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 736 this_effect, this_control); |
730 } | 737 } |
731 | 738 |
732 // Load the length of the {receiver}. | 739 // Load the length of the {receiver}. |
733 Node* this_length = this_effect = | 740 Node* this_length = this_effect = |
734 receiver_is_jsarray | 741 receiver_is_jsarray |
735 ? graph()->NewNode( | 742 ? graph()->NewNode( |
736 simplified()->LoadField( | 743 simplified()->LoadField( |
737 AccessBuilder::ForJSArrayLength(elements_kind)), | 744 AccessBuilder::ForJSArrayLength(elements_kind)), |
738 this_receiver, this_effect, this_control) | 745 this_receiver, this_effect, this_control) |
739 : graph()->NewNode( | 746 : graph()->NewNode( |
740 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), | 747 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), |
741 this_elements, this_effect, this_control); | 748 this_elements, this_effect, this_control); |
742 | 749 |
743 // Check that the {index} is in the valid range for the {receiver}. | 750 // Check that the {index} is in the valid range for the {receiver}. |
744 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index, | 751 Node* check = graph()->NewNode(simplified()->NumberLessThan(), this_index, |
745 this_length); | 752 this_length); |
746 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 753 this_control = this_effect = |
747 frame_state, this_effect, this_control); | 754 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 755 this_effect, this_control); |
748 | 756 |
749 // Compute the element access. | 757 // Compute the element access. |
750 Type* element_type = Type::Any(); | 758 Type* element_type = Type::Any(); |
751 MachineType element_machine_type = MachineType::AnyTagged(); | 759 MachineType element_machine_type = MachineType::AnyTagged(); |
752 if (IsFastDoubleElementsKind(elements_kind)) { | 760 if (IsFastDoubleElementsKind(elements_kind)) { |
753 element_type = Type::Number(); | 761 element_type = Type::Number(); |
754 element_machine_type = MachineType::Float64(); | 762 element_machine_type = MachineType::Float64(); |
755 } else if (IsFastSmiElementsKind(elements_kind)) { | 763 } else if (IsFastSmiElementsKind(elements_kind)) { |
756 element_type = type_cache_.kSmi; | 764 element_type = type_cache_.kSmi; |
757 } | 765 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
801 // Turn the hole into undefined. | 809 // Turn the hole into undefined. |
802 this_control = | 810 this_control = |
803 graph()->NewNode(common()->Merge(2), if_true, if_false); | 811 graph()->NewNode(common()->Merge(2), if_true, if_false); |
804 this_value = graph()->NewNode( | 812 this_value = graph()->NewNode( |
805 common()->Phi(MachineRepresentation::kTagged, 2), | 813 common()->Phi(MachineRepresentation::kTagged, 2), |
806 jsgraph()->UndefinedConstant(), this_value, this_control); | 814 jsgraph()->UndefinedConstant(), this_value, this_control); |
807 element_type = | 815 element_type = |
808 Type::Union(element_type, Type::Undefined(), graph()->zone()); | 816 Type::Union(element_type, Type::Undefined(), graph()->zone()); |
809 } else { | 817 } else { |
810 // Deoptimize in case of the hole. | 818 // Deoptimize in case of the hole. |
811 this_control = | 819 this_control = this_effect = |
812 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, | 820 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, |
813 this_effect, this_control); | 821 this_effect, this_control); |
814 } | 822 } |
815 // Rename the result to represent the actual type (not polluted by the | 823 // Rename the result to represent the actual type (not polluted by the |
816 // hole). | 824 // hole). |
817 this_value = graph()->NewNode(simplified()->TypeGuard(element_type), | 825 this_value = graph()->NewNode(simplified()->TypeGuard(element_type), |
818 this_value, this_control); | 826 this_value, this_control); |
819 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { | 827 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { |
820 // Perform the hole check on the result. | 828 // Perform the hole check on the result. |
821 Node* check = | 829 Node* check = |
822 graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value); | 830 graph()->NewNode(simplified()->NumberIsHoleNaN(), this_value); |
823 // Check if we are allowed to return the hole directly. | 831 // Check if we are allowed to return the hole directly. |
824 Type* initial_holey_array_type = Type::Class( | 832 Type* initial_holey_array_type = Type::Class( |
825 handle(isolate()->get_initial_js_array_map(elements_kind)), | 833 handle(isolate()->get_initial_js_array_map(elements_kind)), |
826 graph()->zone()); | 834 graph()->zone()); |
827 if (receiver_type->NowIs(initial_holey_array_type) && | 835 if (receiver_type->NowIs(initial_holey_array_type) && |
828 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | 836 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
829 // Add a code dependency on the array protector cell. | 837 // Add a code dependency on the array protector cell. |
830 AssumePrototypesStable(receiver_type, native_context, | 838 AssumePrototypesStable(receiver_type, native_context, |
831 isolate()->initial_object_prototype()); | 839 isolate()->initial_object_prototype()); |
832 dependencies()->AssumePropertyCell(factory()->array_protector()); | 840 dependencies()->AssumePropertyCell(factory()->array_protector()); |
833 // Turn the hole into undefined. | 841 // Turn the hole into undefined. |
834 this_value = graph()->NewNode( | 842 this_value = graph()->NewNode( |
835 common()->Select(MachineRepresentation::kTagged, | 843 common()->Select(MachineRepresentation::kTagged, |
836 BranchHint::kFalse), | 844 BranchHint::kFalse), |
837 check, jsgraph()->UndefinedConstant(), this_value); | 845 check, jsgraph()->UndefinedConstant(), this_value); |
838 } else { | 846 } else { |
839 // Deoptimize in case of the hole. | 847 // Deoptimize in case of the hole. |
840 this_control = | 848 this_control = this_effect = |
841 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, | 849 graph()->NewNode(common()->DeoptimizeIf(), check, frame_state, |
842 this_effect, this_control); | 850 this_effect, this_control); |
843 } | 851 } |
844 } | 852 } |
845 } else { | 853 } else { |
846 DCHECK_EQ(AccessMode::kStore, access_mode); | 854 DCHECK_EQ(AccessMode::kStore, access_mode); |
847 if (IsFastSmiElementsKind(elements_kind)) { | 855 if (IsFastSmiElementsKind(elements_kind)) { |
848 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); | 856 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), this_value); |
849 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 857 this_control = this_effect = |
850 frame_state, this_effect, this_control); | 858 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 859 this_effect, this_control); |
851 this_value = graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi), | 860 this_value = graph()->NewNode(simplified()->TypeGuard(type_cache_.kSmi), |
852 this_value, this_control); | 861 this_value, this_control); |
853 } else if (IsFastDoubleElementsKind(elements_kind)) { | 862 } else if (IsFastDoubleElementsKind(elements_kind)) { |
854 Node* check = | 863 Node* check = |
855 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); | 864 graph()->NewNode(simplified()->ObjectIsNumber(), this_value); |
856 this_control = graph()->NewNode(common()->DeoptimizeUnless(), check, | 865 this_control = this_effect = |
857 frame_state, this_effect, this_control); | 866 graph()->NewNode(common()->DeoptimizeUnless(), check, frame_state, |
| 867 this_effect, this_control); |
858 this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()), | 868 this_value = graph()->NewNode(simplified()->TypeGuard(Type::Number()), |
859 this_value, this_control); | 869 this_value, this_control); |
860 } | 870 } |
861 this_effect = graph()->NewNode(simplified()->StoreElement(element_access), | 871 this_effect = graph()->NewNode(simplified()->StoreElement(element_access), |
862 this_elements, this_index, this_value, | 872 this_elements, this_index, this_value, |
863 this_effect, this_control); | 873 this_effect, this_control); |
864 } | 874 } |
865 | 875 |
866 // Remember the final state for this element access. | 876 // Remember the final state for this element access. |
867 values.push_back(this_value); | 877 values.push_back(this_value); |
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1144 } | 1154 } |
1145 | 1155 |
1146 | 1156 |
1147 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1157 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1148 return jsgraph()->simplified(); | 1158 return jsgraph()->simplified(); |
1149 } | 1159 } |
1150 | 1160 |
1151 } // namespace compiler | 1161 } // namespace compiler |
1152 } // namespace internal | 1162 } // namespace internal |
1153 } // namespace v8 | 1163 } // namespace v8 |
OLD | NEW |