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 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), | 347 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
348 index, jsgraph()->HeapConstant(name)); | 348 index, jsgraph()->HeapConstant(name)); |
349 Node* branch = | 349 Node* branch = |
350 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); | 350 graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control); |
351 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); | 351 exit_controls.push_back(graph()->NewNode(common()->IfFalse(), branch)); |
352 control = graph()->NewNode(common()->IfTrue(), branch); | 352 control = graph()->NewNode(common()->IfTrue(), branch); |
353 } | 353 } |
354 | 354 |
355 // Ensure that {receiver} is a heap object. | 355 // Ensure that {receiver} is a heap object. |
356 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 356 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
357 Node* branch = | 357 Node* branch = graph()->NewNode(common()->Branch(), check, control); |
358 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); | |
359 exit_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | |
360 control = graph()->NewNode(common()->IfFalse(), branch); | 358 control = graph()->NewNode(common()->IfFalse(), branch); |
| 359 Node* receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
| 360 Node* receiverissmi_effect = effect; |
361 | 361 |
362 // Load the {receiver} map. The resulting effect is the dominating effect for | 362 // Load the {receiver} map. The resulting effect is the dominating effect for |
363 // all (polymorphic) branches. | 363 // all (polymorphic) branches. |
364 Node* receiver_map = effect = | 364 Node* receiver_map = effect = |
365 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 365 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
366 receiver, effect, control); | 366 receiver, effect, control); |
367 | 367 |
368 // Generate code for the various different property access patterns. | 368 // Generate code for the various different property access patterns. |
369 Node* fallthrough_control = control; | 369 Node* fallthrough_control = control; |
370 for (PropertyAccessInfo const& access_info : access_infos) { | 370 for (PropertyAccessInfo const& access_info : access_infos) { |
(...skipping 10 matching lines...) Expand all Loading... |
381 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), | 381 simplified()->LoadField(AccessBuilder::ForMapInstanceType()), |
382 receiver_map, this_effect, fallthrough_control); | 382 receiver_map, this_effect, fallthrough_control); |
383 Node* check = | 383 Node* check = |
384 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type, | 384 graph()->NewNode(machine()->Uint32LessThan(), receiver_instance_type, |
385 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); | 385 jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE)); |
386 Node* branch = | 386 Node* branch = |
387 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 387 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
388 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 388 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
389 this_control = graph()->NewNode(common()->IfTrue(), branch); | 389 this_control = graph()->NewNode(common()->IfTrue(), branch); |
390 } else { | 390 } else { |
391 // Emit a (sequence of) map checks for other properties. | 391 // Emit a (sequence of) map checks for other {receiver}s. |
392 ZoneVector<Node*> this_controls(zone()); | 392 ZoneVector<Node*> this_controls(zone()); |
| 393 ZoneVector<Node*> this_effects(zone()); |
393 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); | 394 for (auto i = access_info.receiver_type()->Classes(); !i.Done(); |
394 i.Advance()) { | 395 i.Advance()) { |
395 Handle<Map> map = i.Current(); | 396 Handle<Map> map = i.Current(); |
396 Node* check = | 397 Node* check = |
397 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), | 398 graph()->NewNode(simplified()->ReferenceEqual(Type::Internal()), |
398 receiver_map, jsgraph()->Constant(map)); | 399 receiver_map, jsgraph()->Constant(map)); |
399 Node* branch = | 400 Node* branch = |
400 graph()->NewNode(common()->Branch(), check, fallthrough_control); | 401 graph()->NewNode(common()->Branch(), check, fallthrough_control); |
| 402 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); |
401 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); | 403 this_controls.push_back(graph()->NewNode(common()->IfTrue(), branch)); |
402 fallthrough_control = graph()->NewNode(common()->IfFalse(), branch); | 404 this_effects.push_back(this_effect); |
403 } | 405 } |
| 406 |
| 407 // The Number case requires special treatment to also deal with Smis. |
| 408 if (receiver_type->Is(Type::Number())) { |
| 409 // Join this check with the "receiver is smi" check above, and mark the |
| 410 // "receiver is smi" check as "consumed" so that we don't deoptimize if |
| 411 // the {receiver} is actually a Smi. |
| 412 if (receiverissmi_control != nullptr) { |
| 413 this_controls.push_back(receiverissmi_control); |
| 414 this_effects.push_back(receiverissmi_effect); |
| 415 receiverissmi_control = receiverissmi_effect = nullptr; |
| 416 } |
| 417 } |
| 418 |
| 419 // Create dominating Merge+EffectPhi for this {receiver} type. |
404 int const this_control_count = static_cast<int>(this_controls.size()); | 420 int const this_control_count = static_cast<int>(this_controls.size()); |
405 this_control = | 421 this_control = |
406 (this_control_count == 1) | 422 (this_control_count == 1) |
407 ? this_controls.front() | 423 ? this_controls.front() |
408 : graph()->NewNode(common()->Merge(this_control_count), | 424 : graph()->NewNode(common()->Merge(this_control_count), |
409 this_control_count, &this_controls.front()); | 425 this_control_count, &this_controls.front()); |
| 426 this_effects.push_back(this_control); |
| 427 int const this_effect_count = static_cast<int>(this_effects.size()); |
| 428 this_effect = |
| 429 (this_control_count == 1) |
| 430 ? this_effects.front() |
| 431 : graph()->NewNode(common()->EffectPhi(this_control_count), |
| 432 this_effect_count, &this_effects.front()); |
410 } | 433 } |
411 | 434 |
412 // Determine actual holder and perform prototype chain checks. | 435 // Determine actual holder and perform prototype chain checks. |
413 Handle<JSObject> holder; | 436 Handle<JSObject> holder; |
414 if (access_info.holder().ToHandle(&holder)) { | 437 if (access_info.holder().ToHandle(&holder)) { |
415 AssumePrototypesStable(receiver_type, holder); | 438 AssumePrototypesStable(receiver_type, holder); |
416 } | 439 } |
417 | 440 |
418 // Generate the actual property access. | 441 // Generate the actual property access. |
419 if (access_info.IsNotFound()) { | 442 if (access_info.IsNotFound()) { |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 | 600 |
578 // Remember the final state for this property access. | 601 // Remember the final state for this property access. |
579 values.push_back(this_value); | 602 values.push_back(this_value); |
580 effects.push_back(this_effect); | 603 effects.push_back(this_effect); |
581 controls.push_back(this_control); | 604 controls.push_back(this_control); |
582 } | 605 } |
583 | 606 |
584 // Collect the fallthrough control as final "exit" control. | 607 // Collect the fallthrough control as final "exit" control. |
585 if (fallthrough_control != control) { | 608 if (fallthrough_control != control) { |
586 // Mark the last fallthrough branch as deferred. | 609 // Mark the last fallthrough branch as deferred. |
587 Node* branch = NodeProperties::GetControlInput(fallthrough_control); | 610 MarkAsDeferred(fallthrough_control); |
588 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | |
589 if (fallthrough_control->opcode() == IrOpcode::kIfTrue) { | |
590 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse)); | |
591 } else { | |
592 DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode()); | |
593 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue)); | |
594 } | |
595 } | 611 } |
596 exit_controls.push_back(fallthrough_control); | 612 exit_controls.push_back(fallthrough_control); |
597 | 613 |
| 614 // Also collect the "receiver is smi" control if we didn't handle the case of |
| 615 // Number primitives in the polymorphic branches above. |
| 616 if (receiverissmi_control != nullptr) { |
| 617 // Mark the "receiver is smi" case as deferred. |
| 618 MarkAsDeferred(receiverissmi_control); |
| 619 DCHECK_EQ(exit_effect, receiverissmi_effect); |
| 620 exit_controls.push_back(receiverissmi_control); |
| 621 } |
| 622 |
598 // Generate the single "exit" point, where we get if either all map/instance | 623 // Generate the single "exit" point, where we get if either all map/instance |
599 // type checks failed, or one of the assumptions inside one of the cases | 624 // type checks failed, or one of the assumptions inside one of the cases |
600 // failes (i.e. failing prototype chain check). | 625 // failes (i.e. failing prototype chain check). |
601 // TODO(bmeurer): Consider falling back to IC here if deoptimization is | 626 // TODO(bmeurer): Consider falling back to IC here if deoptimization is |
602 // disabled. | 627 // disabled. |
603 int const exit_control_count = static_cast<int>(exit_controls.size()); | 628 int const exit_control_count = static_cast<int>(exit_controls.size()); |
604 Node* exit_control = | 629 Node* exit_control = |
605 (exit_control_count == 1) | 630 (exit_control_count == 1) |
606 ? exit_controls.front() | 631 ? exit_controls.front() |
607 : graph()->NewNode(common()->Merge(exit_control_count), | 632 : graph()->NewNode(common()->Merge(exit_control_count), |
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
869 | 894 |
870 // Remember the final state for this element access. | 895 // Remember the final state for this element access. |
871 values.push_back(this_value); | 896 values.push_back(this_value); |
872 effects.push_back(this_effect); | 897 effects.push_back(this_effect); |
873 controls.push_back(this_control); | 898 controls.push_back(this_control); |
874 } | 899 } |
875 | 900 |
876 // Collect the fallthrough control as final "exit" control. | 901 // Collect the fallthrough control as final "exit" control. |
877 if (fallthrough_control != control) { | 902 if (fallthrough_control != control) { |
878 // Mark the last fallthrough branch as deferred. | 903 // Mark the last fallthrough branch as deferred. |
879 Node* branch = NodeProperties::GetControlInput(fallthrough_control); | 904 MarkAsDeferred(fallthrough_control); |
880 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); | |
881 if (fallthrough_control->opcode() == IrOpcode::kIfTrue) { | |
882 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse)); | |
883 } else { | |
884 DCHECK_EQ(IrOpcode::kIfFalse, fallthrough_control->opcode()); | |
885 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue)); | |
886 } | |
887 } | 905 } |
888 exit_controls.push_back(fallthrough_control); | 906 exit_controls.push_back(fallthrough_control); |
889 | 907 |
890 // Generate the single "exit" point, where we get if either all map/instance | 908 // Generate the single "exit" point, where we get if either all map/instance |
891 // type checks failed, or one of the assumptions inside one of the cases | 909 // type checks failed, or one of the assumptions inside one of the cases |
892 // failes (i.e. failing prototype chain check). | 910 // failes (i.e. failing prototype chain check). |
893 // TODO(bmeurer): Consider falling back to IC here if deoptimization is | 911 // TODO(bmeurer): Consider falling back to IC here if deoptimization is |
894 // disabled. | 912 // disabled. |
895 int const exit_control_count = static_cast<int>(exit_controls.size()); | 913 int const exit_control_count = static_cast<int>(exit_controls.size()); |
896 Node* exit_control = | 914 Node* exit_control = |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1046 Handle<JSReceiver> const prototype = | 1064 Handle<JSReceiver> const prototype = |
1047 PrototypeIterator::GetCurrent<JSReceiver>(j); | 1065 PrototypeIterator::GetCurrent<JSReceiver>(j); |
1048 dependencies()->AssumeMapStable(handle(prototype->map(), isolate())); | 1066 dependencies()->AssumeMapStable(handle(prototype->map(), isolate())); |
1049 // Stop once we get to the holder. | 1067 // Stop once we get to the holder. |
1050 if (prototype.is_identical_to(holder)) break; | 1068 if (prototype.is_identical_to(holder)) break; |
1051 } | 1069 } |
1052 } | 1070 } |
1053 } | 1071 } |
1054 | 1072 |
1055 | 1073 |
| 1074 void JSNativeContextSpecialization::MarkAsDeferred(Node* if_projection) { |
| 1075 Node* branch = NodeProperties::GetControlInput(if_projection); |
| 1076 DCHECK_EQ(IrOpcode::kBranch, branch->opcode()); |
| 1077 if (if_projection->opcode() == IrOpcode::kIfTrue) { |
| 1078 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kFalse)); |
| 1079 } else { |
| 1080 DCHECK_EQ(IrOpcode::kIfFalse, if_projection->opcode()); |
| 1081 NodeProperties::ChangeOp(branch, common()->Branch(BranchHint::kTrue)); |
| 1082 } |
| 1083 } |
| 1084 |
| 1085 |
1056 Graph* JSNativeContextSpecialization::graph() const { | 1086 Graph* JSNativeContextSpecialization::graph() const { |
1057 return jsgraph()->graph(); | 1087 return jsgraph()->graph(); |
1058 } | 1088 } |
1059 | 1089 |
1060 | 1090 |
1061 Isolate* JSNativeContextSpecialization::isolate() const { | 1091 Isolate* JSNativeContextSpecialization::isolate() const { |
1062 return jsgraph()->isolate(); | 1092 return jsgraph()->isolate(); |
1063 } | 1093 } |
1064 | 1094 |
1065 | 1095 |
(...skipping 17 matching lines...) Expand all Loading... |
1083 } | 1113 } |
1084 | 1114 |
1085 | 1115 |
1086 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1116 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1087 return jsgraph()->simplified(); | 1117 return jsgraph()->simplified(); |
1088 } | 1118 } |
1089 | 1119 |
1090 } // namespace compiler | 1120 } // namespace compiler |
1091 } // namespace internal | 1121 } // namespace internal |
1092 } // namespace v8 | 1122 } // namespace v8 |
OLD | NEW |