Chromium Code Reviews| 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 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 } | 136 } |
| 137 | 137 |
| 138 // Ensure that {index} matches the specified {name} (if {index} is given). | 138 // Ensure that {index} matches the specified {name} (if {index} is given). |
| 139 if (index != nullptr) { | 139 if (index != nullptr) { |
| 140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), | 140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
| 141 index, jsgraph()->HeapConstant(name)); | 141 index, jsgraph()->HeapConstant(name)); |
| 142 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 142 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
| 143 } | 143 } |
| 144 | 144 |
| 145 // Check for the monomorphic cases. | 145 // Check for the monomorphic cases. |
| 146 if (access_infos.size() == 1 && | 146 if (access_infos.size() == 1) { |
| 147 HasOnlyStringMaps(access_infos[0].receiver_maps())) { | 147 PropertyAccessInfo access_info = access_infos.front(); |
| 148 // Monormorphic string access (ignoring the fact that there are multiple | 148 if (HasOnlyStringMaps(access_info.receiver_maps())) { |
| 149 // String maps). | 149 // Monormorphic string access (ignoring the fact that there are multiple |
| 150 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver, | 150 // String maps). |
| 151 effect, control); | 151 receiver = effect = graph()->NewNode(simplified()->CheckString(), |
| 152 receiver, effect, control); | |
| 153 } else if (HasOnlyNumberMaps(access_info.receiver_maps())) { | |
| 154 // Monomorphic number access (we also deal with Smis here). | |
| 155 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), | |
| 156 receiver, effect, control); | |
| 157 } else { | |
| 158 // Monomorphic property access. | |
| 159 effect = BuildCheckTaggedPointer(receiver, effect, control); | |
| 160 effect = BuildCheckMaps(receiver, effect, control, | |
| 161 access_info.receiver_maps()); | |
| 162 } | |
| 152 | 163 |
| 153 // Generate the actual property access. | 164 // Generate the actual property access. |
| 154 ValueEffectControl continuation = | 165 ValueEffectControl continuation = |
| 155 BuildPropertyAccess(receiver, value, effect, control, name, | 166 BuildPropertyAccess(receiver, value, effect, control, name, |
| 156 native_context, access_infos[0], access_mode); | 167 native_context, access_info, access_mode); |
| 157 value = continuation.value(); | 168 value = continuation.value(); |
| 158 effect = continuation.effect(); | 169 effect = continuation.effect(); |
| 159 control = continuation.control(); | 170 control = continuation.control(); |
| 160 } else if (access_infos.size() == 1 && | |
| 161 HasOnlyNumberMaps(access_infos[0].receiver_maps())) { | |
| 162 // Monomorphic number access (we also deal with Smis here). | |
| 163 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), receiver, | |
| 164 effect, control); | |
| 165 | |
| 166 // Generate the actual property access. | |
| 167 ValueEffectControl continuation = | |
| 168 BuildPropertyAccess(receiver, value, effect, control, name, | |
| 169 native_context, access_infos[0], access_mode); | |
| 170 value = continuation.value(); | |
| 171 effect = continuation.effect(); | |
| 172 control = continuation.control(); | |
| 173 } else { | 171 } else { |
| 174 // The final states for every polymorphic branch. We join them with | 172 // The final states for every polymorphic branch. We join them with |
| 175 // Merge+Phi+EffectPhi at the bottom. | 173 // Merge+Phi+EffectPhi at the bottom. |
| 176 ZoneVector<Node*> values(zone()); | 174 ZoneVector<Node*> values(zone()); |
| 177 ZoneVector<Node*> effects(zone()); | 175 ZoneVector<Node*> effects(zone()); |
| 178 ZoneVector<Node*> controls(zone()); | 176 ZoneVector<Node*> controls(zone()); |
| 179 | 177 |
| 180 // Check if {receiver} may be a number. | 178 // Check if {receiver} may be a number. |
| 181 bool receiverissmi_possible = false; | 179 bool receiverissmi_possible = false; |
| 182 for (PropertyAccessInfo const& access_info : access_infos) { | 180 for (PropertyAccessInfo const& access_info : access_infos) { |
| 183 if (HasNumberMaps(access_info.receiver_maps())) { | 181 if (HasNumberMaps(access_info.receiver_maps())) { |
| 184 receiverissmi_possible = true; | 182 receiverissmi_possible = true; |
| 185 break; | 183 break; |
| 186 } | 184 } |
| 187 } | 185 } |
| 188 | 186 |
| 189 // Ensure that {receiver} is a heap object. | 187 // Ensure that {receiver} is a heap object. |
| 190 Node* receiverissmi_control = nullptr; | 188 Node* receiverissmi_control = nullptr; |
| 191 Node* receiverissmi_effect = effect; | 189 Node* receiverissmi_effect = effect; |
| 192 if (receiverissmi_possible) { | 190 if (receiverissmi_possible) { |
| 193 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 191 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
| 194 Node* branch = graph()->NewNode(common()->Branch(), check, control); | 192 Node* branch = graph()->NewNode(common()->Branch(), check, control); |
| 195 control = graph()->NewNode(common()->IfFalse(), branch); | 193 control = graph()->NewNode(common()->IfFalse(), branch); |
| 196 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); | 194 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
| 197 receiverissmi_effect = effect; | 195 receiverissmi_effect = effect; |
| 198 } else { | 196 } else { |
| 199 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), | 197 effect = BuildCheckTaggedPointer(receiver, effect, control); |
| 200 receiver, effect, control); | |
| 201 } | 198 } |
| 202 | 199 |
| 203 // Load the {receiver} map. The resulting effect is the dominating effect | 200 // Load the {receiver} map. The resulting effect is the dominating effect |
| 204 // for all (polymorphic) branches. | 201 // for all (polymorphic) branches. |
| 205 Node* receiver_map = effect = | 202 Node* receiver_map = effect = |
| 206 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 203 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 207 receiver, effect, control); | 204 receiver, effect, control); |
| 208 | 205 |
| 209 // Generate code for the various different property access patterns. | 206 // Generate code for the various different property access patterns. |
| 210 Node* fallthrough_control = control; | 207 Node* fallthrough_control = control; |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 &access_infos)) { | 424 &access_infos)) { |
| 428 return NoChange(); | 425 return NoChange(); |
| 429 } | 426 } |
| 430 | 427 |
| 431 // Nothing to do if we have no non-deprecated maps. | 428 // Nothing to do if we have no non-deprecated maps. |
| 432 if (access_infos.empty()) { | 429 if (access_infos.empty()) { |
| 433 return ReduceSoftDeoptimize( | 430 return ReduceSoftDeoptimize( |
| 434 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); | 431 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); |
| 435 } | 432 } |
| 436 | 433 |
| 437 // The final states for every polymorphic branch. We join them with | 434 // Ensure that {receiver} is a heap object. |
| 438 // Merge+Phi+EffectPhi at the bottom. | 435 effect = BuildCheckTaggedPointer(receiver, effect, control); |
| 439 ZoneVector<Node*> values(zone()); | |
| 440 ZoneVector<Node*> effects(zone()); | |
| 441 ZoneVector<Node*> controls(zone()); | |
| 442 | 436 |
| 443 // Ensure that {receiver} is a heap object. | 437 // Check for the monomorphic case. |
| 444 receiver = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), | 438 if (access_infos.size() == 1) { |
| 445 receiver, effect, control); | 439 ElementAccessInfo access_info = access_infos.front(); |
| 446 | |
| 447 // Generate code for the various different element access patterns. | |
| 448 Node* fallthrough_control = control; | |
| 449 for (size_t j = 0; j < access_infos.size(); ++j) { | |
| 450 ElementAccessInfo const& access_info = access_infos[j]; | |
| 451 Node* this_receiver = receiver; | |
| 452 Node* this_value = value; | |
| 453 Node* this_index = index; | |
| 454 Node* this_effect = effect; | |
| 455 Node* this_control = fallthrough_control; | |
| 456 | 440 |
| 457 // Perform possible elements kind transitions. | 441 // Perform possible elements kind transitions. |
| 458 for (auto transition : access_info.transitions()) { | 442 for (auto transition : access_info.transitions()) { |
| 459 Handle<Map> const transition_source = transition.first; | 443 Handle<Map> const transition_source = transition.first; |
| 460 Handle<Map> const transition_target = transition.second; | 444 Handle<Map> const transition_target = transition.second; |
| 461 this_effect = graph()->NewNode( | 445 effect = graph()->NewNode( |
| 462 simplified()->TransitionElementsKind( | 446 simplified()->TransitionElementsKind( |
| 463 IsSimpleMapChangeTransition(transition_source->elements_kind(), | 447 IsSimpleMapChangeTransition(transition_source->elements_kind(), |
| 464 transition_target->elements_kind()) | 448 transition_target->elements_kind()) |
| 465 ? ElementsTransition::kFastTransition | 449 ? ElementsTransition::kFastTransition |
| 466 : ElementsTransition::kSlowTransition), | 450 : ElementsTransition::kSlowTransition), |
| 467 receiver, jsgraph()->HeapConstant(transition_source), | 451 receiver, jsgraph()->HeapConstant(transition_source), |
| 468 jsgraph()->HeapConstant(transition_target), this_effect, | 452 jsgraph()->HeapConstant(transition_target), effect, control); |
| 469 this_control); | |
| 470 } | 453 } |
| 471 | 454 |
| 472 // Load the {receiver} map. | 455 // TODO(turbofan): The effect/control linearization will not find a |
| 473 Node* receiver_map = this_effect = | 456 // FrameState after the StoreField or Call that is generated for the |
| 474 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 457 // elements kind transition above. This is because those operators |
| 475 receiver, this_effect, this_control); | 458 // don't have the kNoWrite flag on it, even though they are not |
| 459 // observable by JavaScript. | |
| 460 effect = | |
| 461 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); | |
| 476 | 462 |
| 477 // Perform map check on {receiver}. | 463 // Perform map check on the {receiver}. |
| 478 MapList const& receiver_maps = access_info.receiver_maps(); | 464 effect = |
| 479 { | 465 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); |
| 480 ZoneVector<Node*> this_controls(zone()); | 466 |
| 481 ZoneVector<Node*> this_effects(zone()); | 467 // Access the actual element. |
| 482 size_t num_classes = receiver_maps.size(); | 468 ValueEffectControl continuation = |
| 483 for (Handle<Map> map : receiver_maps) { | 469 BuildElementAccess(receiver, index, value, effect, control, |
| 484 DCHECK_LT(0u, num_classes); | 470 native_context, access_info, access_mode); |
| 485 Node* check = | 471 value = continuation.value(); |
| 486 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), | 472 effect = continuation.effect(); |
| 487 receiver_map, jsgraph()->Constant(map)); | 473 control = continuation.control(); |
| 488 if (--num_classes == 0 && j == access_infos.size() - 1) { | 474 } else { |
| 489 // Last map check on the fallthrough control path, do a conditional | 475 // The final states for every polymorphic branch. We join them with |
| 490 // eager deoptimization exit here. | 476 // Merge+Phi+EffectPhi at the bottom. |
| 491 // TODO(turbofan): This is ugly as hell! We should probably introduce | 477 ZoneVector<Node*> values(zone()); |
| 492 // macro-ish operators for property access that encapsulate this whole | 478 ZoneVector<Node*> effects(zone()); |
| 493 // mess. | 479 ZoneVector<Node*> controls(zone()); |
| 494 check = graph()->NewNode(simplified()->CheckIf(), check, this_effect, | 480 |
| 495 this_control); | 481 // Generate code for the various different element access patterns. |
| 496 this_controls.push_back(this_control); | 482 Node* fallthrough_control = control; |
| 497 this_effects.push_back(check); | 483 for (size_t j = 0; j < access_infos.size(); ++j) { |
| 498 fallthrough_control = nullptr; | 484 ElementAccessInfo const& access_info = access_infos[j]; |
| 485 Node* this_receiver = receiver; | |
| 486 Node* this_value = value; | |
| 487 Node* this_index = index; | |
| 488 Node* this_effect = effect; | |
| 489 Node* this_control = fallthrough_control; | |
| 490 | |
| 491 // Perform possible elements kind transitions. | |
| 492 for (auto transition : access_info.transitions()) { | |
| 493 Handle<Map> const transition_source = transition.first; | |
| 494 Handle<Map> const transition_target = transition.second; | |
| 495 this_effect = graph()->NewNode( | |
| 496 simplified()->TransitionElementsKind( | |
| 497 IsSimpleMapChangeTransition(transition_source->elements_kind(), | |
| 498 transition_target->elements_kind()) | |
| 499 ? ElementsTransition::kFastTransition | |
| 500 : ElementsTransition::kSlowTransition), | |
| 501 receiver, jsgraph()->HeapConstant(transition_source), | |
| 502 jsgraph()->HeapConstant(transition_target), this_effect, | |
| 503 this_control); | |
| 504 } | |
| 505 | |
| 506 // Load the {receiver} map. | |
| 507 Node* receiver_map = this_effect = | |
| 508 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | |
| 509 receiver, this_effect, this_control); | |
| 510 | |
| 511 // Perform map check(s) on {receiver}. | |
| 512 MapList const& receiver_maps = access_info.receiver_maps(); | |
| 513 { | |
| 514 ZoneVector<Node*> this_controls(zone()); | |
| 515 ZoneVector<Node*> this_effects(zone()); | |
| 516 size_t num_classes = receiver_maps.size(); | |
| 517 for (Handle<Map> map : receiver_maps) { | |
| 518 DCHECK_LT(0u, num_classes); | |
| 519 Node* check = | |
| 520 graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), | |
| 521 receiver_map, jsgraph()->Constant(map)); | |
| 522 if (--num_classes == 0 && j == access_infos.size() - 1) { | |
| 523 // Last map check on the fallthrough control path, do a conditional | |
| 524 // eager deoptimization exit here. | |
| 525 // TODO(turbofan): This is ugly as hell! We should probably | |
| 526 // introduce macro-ish operators for property access that | |
| 527 // encapsulate this whole mess. | |
| 528 check = graph()->NewNode(simplified()->CheckIf(), check, | |
| 529 this_effect, this_control); | |
| 530 this_controls.push_back(this_control); | |
| 531 this_effects.push_back(check); | |
| 532 fallthrough_control = nullptr; | |
| 533 } else { | |
| 534 Node* branch = graph()->NewNode(common()->Branch(), check, | |
| 535 fallthrough_control); | |
| 536 this_controls.push_back( | |
| 537 graph()->NewNode(common()->IfTrue(), branch)); | |
| 538 this_effects.push_back(effect); | |
| 539 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | |
| 540 } | |
| 541 } | |
| 542 | |
| 543 // Create single chokepoint for the control. | |
|
epertoso
2016/07/29 09:34:08
nit: do you mean checkpoint?
Benedikt Meurer
2016/07/29 09:37:48
Yes.
| |
| 544 int const this_control_count = static_cast<int>(this_controls.size()); | |
| 545 if (this_control_count == 1) { | |
| 546 this_control = this_controls.front(); | |
| 547 this_effect = this_effects.front(); | |
| 499 } else { | 548 } else { |
| 500 Node* branch = | 549 this_control = |
| 501 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 550 graph()->NewNode(common()->Merge(this_control_count), |
| 502 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 551 this_control_count, &this_controls.front()); |
| 503 this_effects.push_back(effect); | 552 this_effects.push_back(this_control); |
| 504 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 553 this_effect = |
| 554 graph()->NewNode(common()->EffectPhi(this_control_count), | |
| 555 this_control_count + 1, &this_effects.front()); | |
| 556 | |
| 557 // TODO(turbofan): The effect/control linearization will not find a | |
| 558 // FrameState after the StoreField or Call that is generated for the | |
| 559 // elements kind transition above. This is because those operators | |
| 560 // don't have the kNoWrite flag on it, even though they are not | |
| 561 // observable by JavaScript. | |
| 562 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | |
| 563 this_effect, this_control); | |
| 505 } | 564 } |
| 506 } | 565 } |
| 507 | 566 |
| 508 // Create single chokepoint for the control. | 567 // Certain stores need a prototype chain check because shape changes |
| 509 int const this_control_count = static_cast<int>(this_controls.size()); | 568 // could allow callbacks on elements in the prototype chain that are |
| 510 if (this_control_count == 1) { | 569 // not compatible with (monomorphic) keyed stores. |
| 511 this_control = this_controls.front(); | 570 Handle<JSObject> holder; |
| 512 this_effect = this_effects.front(); | 571 if (access_info.holder().ToHandle(&holder)) { |
| 513 } else { | 572 AssumePrototypesStable(receiver_maps, native_context, holder); |
| 514 this_control = | 573 } |
| 515 graph()->NewNode(common()->Merge(this_control_count), | |
| 516 this_control_count, &this_controls.front()); | |
| 517 this_effects.push_back(this_control); | |
| 518 this_effect = | |
| 519 graph()->NewNode(common()->EffectPhi(this_control_count), | |
| 520 this_control_count + 1, &this_effects.front()); | |
| 521 | 574 |
| 522 // TODO(turbofan): The effect/control linearization will not find a | 575 // Access the actual element. |
| 523 // FrameState after the StoreField or Call that is generated for the | 576 ValueEffectControl continuation = BuildElementAccess( |
| 524 // elements kind transition above. This is because those operators | 577 this_receiver, this_index, this_value, this_effect, this_control, |
| 525 // don't have the kNoWrite flag on it, even though they are not | 578 native_context, access_info, access_mode); |
| 526 // observable by JavaScript. | 579 values.push_back(continuation.value()); |
| 527 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | 580 effects.push_back(continuation.effect()); |
| 528 this_effect, this_control); | 581 controls.push_back(continuation.control()); |
| 529 } | |
| 530 } | 582 } |
| 531 | 583 |
| 532 // Certain stores need a prototype chain check because shape changes | 584 DCHECK_NULL(fallthrough_control); |
| 533 // could allow callbacks on elements in the prototype chain that are | 585 |
| 534 // not compatible with (monomorphic) keyed stores. | 586 // Generate the final merge point for all (polymorphic) branches. |
| 535 Handle<JSObject> holder; | 587 int const control_count = static_cast<int>(controls.size()); |
| 536 if (access_info.holder().ToHandle(&holder)) { | 588 if (control_count == 0) { |
| 537 AssumePrototypesStable(receiver_maps, native_context, holder); | 589 value = effect = control = jsgraph()->Dead(); |
| 590 } else if (control_count == 1) { | |
| 591 value = values.front(); | |
| 592 effect = effects.front(); | |
| 593 control = controls.front(); | |
| 594 } else { | |
| 595 control = graph()->NewNode(common()->Merge(control_count), control_count, | |
| 596 &controls.front()); | |
| 597 values.push_back(control); | |
| 598 value = graph()->NewNode( | |
| 599 common()->Phi(MachineRepresentation::kTagged, control_count), | |
| 600 control_count + 1, &values.front()); | |
| 601 effects.push_back(control); | |
| 602 effect = graph()->NewNode(common()->EffectPhi(control_count), | |
| 603 control_count + 1, &effects.front()); | |
| 538 } | 604 } |
| 539 | |
| 540 // Access the actual element. | |
| 541 ValueEffectControl continuation = BuildElementAccess( | |
| 542 this_receiver, this_index, this_value, this_effect, this_control, | |
| 543 native_context, access_info, access_mode); | |
| 544 values.push_back(continuation.value()); | |
| 545 effects.push_back(continuation.effect()); | |
| 546 controls.push_back(continuation.control()); | |
| 547 } | 605 } |
| 548 | 606 |
| 549 DCHECK_NULL(fallthrough_control); | |
| 550 | |
| 551 // Generate the final merge point for all (polymorphic) branches. | |
| 552 int const control_count = static_cast<int>(controls.size()); | |
| 553 if (control_count == 0) { | |
| 554 value = effect = control = jsgraph()->Dead(); | |
| 555 } else if (control_count == 1) { | |
| 556 value = values.front(); | |
| 557 effect = effects.front(); | |
| 558 control = controls.front(); | |
| 559 } else { | |
| 560 control = graph()->NewNode(common()->Merge(control_count), control_count, | |
| 561 &controls.front()); | |
| 562 values.push_back(control); | |
| 563 value = graph()->NewNode( | |
| 564 common()->Phi(MachineRepresentation::kTagged, control_count), | |
| 565 control_count + 1, &values.front()); | |
| 566 effects.push_back(control); | |
| 567 effect = graph()->NewNode(common()->EffectPhi(control_count), | |
| 568 control_count + 1, &effects.front()); | |
| 569 } | |
| 570 ReplaceWithValue(node, value, effect, control); | 607 ReplaceWithValue(node, value, effect, control); |
| 571 return Replace(value); | 608 return Replace(value); |
| 572 } | 609 } |
| 573 | 610 |
| 574 template <typename KeyedICNexus> | 611 template <typename KeyedICNexus> |
| 575 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( | 612 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( |
| 576 Node* node, Node* index, Node* value, KeyedICNexus const& nexus, | 613 Node* node, Node* index, Node* value, KeyedICNexus const& nexus, |
| 577 AccessMode access_mode, LanguageMode language_mode, | 614 AccessMode access_mode, LanguageMode language_mode, |
| 578 KeyedAccessStoreMode store_mode) { | 615 KeyedAccessStoreMode store_mode) { |
| 579 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || | 616 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 785 field_access.machine_type = MachineType::Float64(); | 822 field_access.machine_type = MachineType::Float64(); |
| 786 } | 823 } |
| 787 } else { | 824 } else { |
| 788 // Unboxed double field, we store directly to the field. | 825 // Unboxed double field, we store directly to the field. |
| 789 field_access.machine_type = MachineType::Float64(); | 826 field_access.machine_type = MachineType::Float64(); |
| 790 } | 827 } |
| 791 } else if (field_type->Is(Type::TaggedSigned())) { | 828 } else if (field_type->Is(Type::TaggedSigned())) { |
| 792 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), | 829 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), |
| 793 value, effect, control); | 830 value, effect, control); |
| 794 } else if (field_type->Is(Type::TaggedPointer())) { | 831 } else if (field_type->Is(Type::TaggedPointer())) { |
| 832 // Ensure that {value} is a HeapObject. | |
| 795 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), | 833 value = effect = graph()->NewNode(simplified()->CheckTaggedPointer(), |
| 796 value, effect, control); | 834 value, effect, control); |
| 797 if (field_type->NumClasses() == 1) { | 835 if (field_type->NumClasses() == 1) { |
| 798 // Emit a map check for the value. | 836 // Emit a map check for the value. |
| 799 Node* value_map = effect = | 837 Node* field_map = |
| 800 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 838 jsgraph()->Constant(field_type->Classes().Current()); |
| 801 value, effect, control); | 839 effect = graph()->NewNode(simplified()->CheckMaps(1), value, |
| 802 Node* check = graph()->NewNode( | 840 field_map, effect, control); |
| 803 simplified()->ReferenceEqual(Type::Internal()), value_map, | |
| 804 jsgraph()->Constant(field_type->Classes().Current())); | |
| 805 effect = | |
| 806 graph()->NewNode(simplified()->CheckIf(), check, effect, control); | |
| 807 } else { | 841 } else { |
| 808 DCHECK_EQ(0, field_type->NumClasses()); | 842 DCHECK_EQ(0, field_type->NumClasses()); |
| 809 } | 843 } |
| 810 } else { | 844 } else { |
| 811 DCHECK(field_type->Is(Type::Tagged())); | 845 DCHECK(field_type->Is(Type::Tagged())); |
| 812 } | 846 } |
| 813 Handle<Map> transition_map; | 847 Handle<Map> transition_map; |
| 814 if (access_info.transition_map().ToHandle(&transition_map)) { | 848 if (access_info.transition_map().ToHandle(&transition_map)) { |
| 815 effect = graph()->NewNode( | 849 effect = graph()->NewNode( |
| 816 common()->BeginRegion(RegionObservability::kObservable), effect); | 850 common()->BeginRegion(RegionObservability::kObservable), effect); |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 960 // Make sure we do not store signalling NaNs into double arrays. | 994 // Make sure we do not store signalling NaNs into double arrays. |
| 961 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); | 995 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); |
| 962 } | 996 } |
| 963 effect = graph()->NewNode(simplified()->StoreElement(element_access), | 997 effect = graph()->NewNode(simplified()->StoreElement(element_access), |
| 964 elements, index, value, effect, control); | 998 elements, index, value, effect, control); |
| 965 } | 999 } |
| 966 | 1000 |
| 967 return ValueEffectControl(value, effect, control); | 1001 return ValueEffectControl(value, effect, control); |
| 968 } | 1002 } |
| 969 | 1003 |
| 1004 Node* JSNativeContextSpecialization::BuildCheckMaps( | |
| 1005 Node* receiver, Node* effect, Node* control, | |
| 1006 std::vector<Handle<Map>> const& maps) { | |
| 1007 HeapObjectMatcher m(receiver); | |
| 1008 if (m.HasValue()) { | |
| 1009 Handle<Map> receiver_map(m.Value()->map(), isolate()); | |
| 1010 if (receiver_map->is_stable()) { | |
| 1011 for (Handle<Map> map : maps) { | |
| 1012 if (map.is_identical_to(receiver_map)) { | |
| 1013 dependencies()->AssumeMapStable(receiver_map); | |
| 1014 return effect; | |
| 1015 } | |
| 1016 } | |
| 1017 } | |
| 1018 } | |
| 1019 int const map_input_count = static_cast<int>(maps.size()); | |
| 1020 int const input_count = 1 + map_input_count + 1 + 1; | |
| 1021 Node** inputs = zone()->NewArray<Node*>(input_count); | |
| 1022 inputs[0] = receiver; | |
| 1023 for (int i = 0; i < map_input_count; ++i) { | |
| 1024 inputs[1 + i] = jsgraph()->HeapConstant(maps[i]); | |
| 1025 } | |
| 1026 inputs[input_count - 2] = effect; | |
| 1027 inputs[input_count - 1] = control; | |
| 1028 return graph()->NewNode(simplified()->CheckMaps(map_input_count), input_count, | |
| 1029 inputs); | |
| 1030 } | |
| 1031 | |
| 1032 Node* JSNativeContextSpecialization::BuildCheckTaggedPointer(Node* receiver, | |
| 1033 Node* effect, | |
| 1034 Node* control) { | |
| 1035 switch (receiver->opcode()) { | |
| 1036 case IrOpcode::kHeapConstant: | |
| 1037 case IrOpcode::kJSCreate: | |
| 1038 case IrOpcode::kJSCreateArguments: | |
| 1039 case IrOpcode::kJSCreateArray: | |
| 1040 case IrOpcode::kJSCreateClosure: | |
| 1041 case IrOpcode::kJSCreateIterResultObject: | |
| 1042 case IrOpcode::kJSCreateLiteralArray: | |
| 1043 case IrOpcode::kJSCreateLiteralObject: | |
| 1044 case IrOpcode::kJSCreateLiteralRegExp: | |
| 1045 case IrOpcode::kJSConvertReceiver: | |
| 1046 case IrOpcode::kJSToName: | |
| 1047 case IrOpcode::kJSToString: | |
| 1048 case IrOpcode::kJSToObject: | |
| 1049 case IrOpcode::kJSTypeOf: { | |
| 1050 return effect; | |
| 1051 } | |
| 1052 default: { | |
| 1053 return graph()->NewNode(simplified()->CheckTaggedPointer(), receiver, | |
| 1054 effect, control); | |
| 1055 } | |
| 1056 } | |
| 1057 } | |
| 1058 | |
| 970 void JSNativeContextSpecialization::AssumePrototypesStable( | 1059 void JSNativeContextSpecialization::AssumePrototypesStable( |
| 971 std::vector<Handle<Map>> const& receiver_maps, | 1060 std::vector<Handle<Map>> const& receiver_maps, |
| 972 Handle<Context> native_context, Handle<JSObject> holder) { | 1061 Handle<Context> native_context, Handle<JSObject> holder) { |
| 973 // Determine actual holder and perform prototype chain checks. | 1062 // Determine actual holder and perform prototype chain checks. |
| 974 for (auto map : receiver_maps) { | 1063 for (auto map : receiver_maps) { |
| 975 // Perform the implicit ToObject for primitives here. | 1064 // Perform the implicit ToObject for primitives here. |
| 976 // Implemented according to ES6 section 7.3.2 GetV (V, P). | 1065 // Implemented according to ES6 section 7.3.2 GetV (V, P). |
| 977 Handle<JSFunction> constructor; | 1066 Handle<JSFunction> constructor; |
| 978 if (Map::GetConstructorFunction(map, native_context) | 1067 if (Map::GetConstructorFunction(map, native_context) |
| 979 .ToHandle(&constructor)) { | 1068 .ToHandle(&constructor)) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1004 } | 1093 } |
| 1005 } | 1094 } |
| 1006 } | 1095 } |
| 1007 return true; | 1096 return true; |
| 1008 } | 1097 } |
| 1009 return false; | 1098 return false; |
| 1010 } | 1099 } |
| 1011 | 1100 |
| 1012 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver, | 1101 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver, |
| 1013 Node* effect) { | 1102 Node* effect) { |
| 1014 NodeMatcher m(receiver); | 1103 HeapObjectMatcher m(receiver); |
| 1015 if (m.IsJSCreate()) { | 1104 if (m.HasValue()) { |
| 1105 Handle<Map> receiver_map(m.Value()->map(), isolate()); | |
| 1106 if (receiver_map->is_stable()) return receiver_map; | |
| 1107 } else if (m.IsJSCreate()) { | |
| 1016 HeapObjectMatcher mtarget(m.InputAt(0)); | 1108 HeapObjectMatcher mtarget(m.InputAt(0)); |
| 1017 HeapObjectMatcher mnewtarget(m.InputAt(1)); | 1109 HeapObjectMatcher mnewtarget(m.InputAt(1)); |
| 1018 if (mtarget.HasValue() && mnewtarget.HasValue()) { | 1110 if (mtarget.HasValue() && mnewtarget.HasValue()) { |
| 1019 Handle<JSFunction> constructor = | 1111 Handle<JSFunction> constructor = |
| 1020 Handle<JSFunction>::cast(mtarget.Value()); | 1112 Handle<JSFunction>::cast(mtarget.Value()); |
| 1021 if (constructor->has_initial_map()) { | 1113 if (constructor->has_initial_map()) { |
| 1022 Handle<Map> initial_map(constructor->initial_map(), isolate()); | 1114 Handle<Map> initial_map(constructor->initial_map(), isolate()); |
| 1023 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) { | 1115 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) { |
| 1024 // Walk up the {effect} chain to see if the {receiver} is the | 1116 // Walk up the {effect} chain to see if the {receiver} is the |
| 1025 // dominating effect and there's no other observable write in | 1117 // dominating effect and there's no other observable write in |
| 1026 // between. | 1118 // between. |
| 1027 while (true) { | 1119 while (true) { |
| 1028 if (receiver == effect) return initial_map; | 1120 if (receiver == effect) return initial_map; |
| 1029 if (!effect->op()->HasProperty(Operator::kNoWrite) || | 1121 if (!effect->op()->HasProperty(Operator::kNoWrite) || |
| 1030 effect->op()->EffectInputCount() != 1) { | 1122 effect->op()->EffectInputCount() != 1) { |
| 1031 break; | 1123 break; |
| 1032 } | 1124 } |
| 1033 effect = NodeProperties::GetEffectInput(effect); | 1125 effect = NodeProperties::GetEffectInput(effect); |
| 1034 } | 1126 } |
| 1035 } | 1127 } |
| 1036 } | 1128 } |
| 1037 } | 1129 } |
| 1038 } | 1130 } |
| 1131 // TODO(turbofan): Go hunting for CheckMaps(receiver) in the effect chain? | |
| 1039 return MaybeHandle<Map>(); | 1132 return MaybeHandle<Map>(); |
| 1040 } | 1133 } |
| 1041 | 1134 |
| 1042 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap( | 1135 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap( |
| 1043 Node* receiver) { | 1136 Node* receiver) { |
| 1044 HeapObjectMatcher m(receiver); | 1137 HeapObjectMatcher m(receiver); |
| 1045 if (m.HasValue()) { | 1138 if (m.HasValue()) { |
| 1046 return handle(m.Value()->map()->FindRootMap(), isolate()); | 1139 return handle(m.Value()->map()->FindRootMap(), isolate()); |
| 1047 } else if (m.IsJSCreate()) { | 1140 } else if (m.IsJSCreate()) { |
| 1048 HeapObjectMatcher mtarget(m.InputAt(0)); | 1141 HeapObjectMatcher mtarget(m.InputAt(0)); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1100 } | 1193 } |
| 1101 | 1194 |
| 1102 | 1195 |
| 1103 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1196 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
| 1104 return jsgraph()->simplified(); | 1197 return jsgraph()->simplified(); |
| 1105 } | 1198 } |
| 1106 | 1199 |
| 1107 } // namespace compiler | 1200 } // namespace compiler |
| 1108 } // namespace internal | 1201 } // namespace internal |
| 1109 } // namespace v8 | 1202 } // namespace v8 |
| OLD | NEW |