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