OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/code-stubs.h" | 5 #include "src/code-stubs.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/compiler/code-stub-assembler.h" | 10 #include "src/compiler/code-stub-assembler.h" |
(...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 void StringLengthStub::GenerateAssembly( | 466 void StringLengthStub::GenerateAssembly( |
467 compiler::CodeStubAssembler* assembler) const { | 467 compiler::CodeStubAssembler* assembler) const { |
468 compiler::Node* value = assembler->Parameter(0); | 468 compiler::Node* value = assembler->Parameter(0); |
469 compiler::Node* string = | 469 compiler::Node* string = |
470 assembler->LoadObjectField(value, JSValue::kValueOffset); | 470 assembler->LoadObjectField(value, JSValue::kValueOffset); |
471 compiler::Node* result = | 471 compiler::Node* result = |
472 assembler->LoadObjectField(string, String::kLengthOffset); | 472 assembler->LoadObjectField(string, String::kLengthOffset); |
473 assembler->Return(result); | 473 assembler->Return(result); |
474 } | 474 } |
475 | 475 |
476 void StrictEqualStub::GenerateAssembly( | 476 namespace { |
477 compiler::CodeStubAssembler* assembler) const { | 477 |
478 // Here's pseudo-code for the algorithm below: | 478 enum StrictEqualMode { kStrictEqual, kStrictNotEqual }; |
| 479 |
| 480 void GenerateStrictEqual(compiler::CodeStubAssembler* assembler, |
| 481 StrictEqualMode mode) { |
| 482 // Here's pseudo-code for the algorithm below in case of kStrictEqual mode; |
| 483 // for kStrictNotEqual mode we properly negate the result. |
479 // | 484 // |
480 // if (lhs == rhs) { | 485 // if (lhs == rhs) { |
481 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; | 486 // if (lhs->IsHeapNumber()) return HeapNumber::cast(lhs)->value() != NaN; |
482 // return true; | 487 // return true; |
483 // } | 488 // } |
484 // if (!lhs->IsSmi()) { | 489 // if (!lhs->IsSmi()) { |
485 // if (lhs->IsHeapNumber()) { | 490 // if (lhs->IsHeapNumber()) { |
486 // if (rhs->IsSmi()) { | 491 // if (rhs->IsSmi()) { |
487 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); | 492 // return Smi::cast(rhs)->value() == HeapNumber::cast(lhs)->value(); |
488 // } else if (rhs->IsHeapNumber()) { | 493 // } else if (rhs->IsHeapNumber()) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 // } | 527 // } |
523 // } | 528 // } |
524 | 529 |
525 typedef compiler::CodeStubAssembler::Label Label; | 530 typedef compiler::CodeStubAssembler::Label Label; |
526 typedef compiler::Node Node; | 531 typedef compiler::Node Node; |
527 | 532 |
528 Node* lhs = assembler->Parameter(0); | 533 Node* lhs = assembler->Parameter(0); |
529 Node* rhs = assembler->Parameter(1); | 534 Node* rhs = assembler->Parameter(1); |
530 Node* context = assembler->Parameter(2); | 535 Node* context = assembler->Parameter(2); |
531 | 536 |
532 Label if_true(assembler), if_false(assembler); | 537 Label if_equal(assembler), if_notequal(assembler); |
533 | 538 |
534 // Check if {lhs} and {rhs} refer to the same object. | 539 // Check if {lhs} and {rhs} refer to the same object. |
535 Label if_same(assembler), if_notsame(assembler); | 540 Label if_same(assembler), if_notsame(assembler); |
536 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); | 541 assembler->Branch(assembler->WordEqual(lhs, rhs), &if_same, &if_notsame); |
537 | 542 |
538 assembler->Bind(&if_same); | 543 assembler->Bind(&if_same); |
539 { | 544 { |
540 // The {lhs} and {rhs} reference the exact same value, yet we need special | 545 // The {lhs} and {rhs} reference the exact same value, yet we need special |
541 // treatment for HeapNumber, as NaN is not equal to NaN. | 546 // treatment for HeapNumber, as NaN is not equal to NaN. |
542 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it | 547 // TODO(bmeurer): This seems to violate the SIMD.js specification, but it |
(...skipping 13 matching lines...) Expand all Loading... |
556 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); | 561 Label if_lhsisnumber(assembler), if_lhsisnotnumber(assembler); |
557 assembler->Branch(assembler->WordEqual(lhs_map, number_map), | 562 assembler->Branch(assembler->WordEqual(lhs_map, number_map), |
558 &if_lhsisnumber, &if_lhsisnotnumber); | 563 &if_lhsisnumber, &if_lhsisnotnumber); |
559 | 564 |
560 assembler->Bind(&if_lhsisnumber); | 565 assembler->Bind(&if_lhsisnumber); |
561 { | 566 { |
562 // Convert {lhs} (and therefore {rhs}) to floating point value. | 567 // Convert {lhs} (and therefore {rhs}) to floating point value. |
563 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | 568 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
564 | 569 |
565 // Check if the HeapNumber value is a NaN. | 570 // Check if the HeapNumber value is a NaN. |
566 assembler->BranchIfFloat64IsNaN(lhs_value, &if_false, &if_true); | 571 assembler->BranchIfFloat64IsNaN(lhs_value, &if_notequal, &if_equal); |
567 } | 572 } |
568 | 573 |
569 assembler->Bind(&if_lhsisnotnumber); | 574 assembler->Bind(&if_lhsisnotnumber); |
570 assembler->Goto(&if_true); | 575 assembler->Goto(&if_equal); |
571 } | 576 } |
572 | 577 |
573 assembler->Bind(&if_lhsissmi); | 578 assembler->Bind(&if_lhsissmi); |
574 assembler->Goto(&if_true); | 579 assembler->Goto(&if_equal); |
575 } | 580 } |
576 | 581 |
577 assembler->Bind(&if_notsame); | 582 assembler->Bind(&if_notsame); |
578 { | 583 { |
579 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, | 584 // The {lhs} and {rhs} reference different objects, yet for Smi, HeapNumber, |
580 // String and Simd128Value they can still be considered equal. | 585 // String and Simd128Value they can still be considered equal. |
581 Node* number_map = assembler->HeapNumberMapConstant(); | 586 Node* number_map = assembler->HeapNumberMapConstant(); |
582 | 587 |
583 // Check if {lhs} is a Smi or a HeapObject. | 588 // Check if {lhs} is a Smi or a HeapObject. |
584 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); | 589 Label if_lhsissmi(assembler), if_lhsisnotsmi(assembler); |
(...skipping 16 matching lines...) Expand all Loading... |
601 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | 606 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
602 &if_rhsisnotsmi); | 607 &if_rhsisnotsmi); |
603 | 608 |
604 assembler->Bind(&if_rhsissmi); | 609 assembler->Bind(&if_rhsissmi); |
605 { | 610 { |
606 // Convert {lhs} and {rhs} to floating point values. | 611 // Convert {lhs} and {rhs} to floating point values. |
607 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | 612 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
608 Node* rhs_value = assembler->SmiToFloat64(rhs); | 613 Node* rhs_value = assembler->SmiToFloat64(rhs); |
609 | 614 |
610 // Perform a floating point comparison of {lhs} and {rhs}. | 615 // Perform a floating point comparison of {lhs} and {rhs}. |
611 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_true, | 616 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, |
612 &if_false); | 617 &if_notequal); |
613 } | 618 } |
614 | 619 |
615 assembler->Bind(&if_rhsisnotsmi); | 620 assembler->Bind(&if_rhsisnotsmi); |
616 { | 621 { |
617 // Load the map of {rhs}. | 622 // Load the map of {rhs}. |
618 Node* rhs_map = | 623 Node* rhs_map = |
619 assembler->LoadObjectField(rhs, HeapObject::kMapOffset); | 624 assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
620 | 625 |
621 // Check if {rhs} is also a HeapNumber. | 626 // Check if {rhs} is also a HeapNumber. |
622 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | 627 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); |
623 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | 628 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
624 &if_rhsisnumber, &if_rhsisnotnumber); | 629 &if_rhsisnumber, &if_rhsisnotnumber); |
625 | 630 |
626 assembler->Bind(&if_rhsisnumber); | 631 assembler->Bind(&if_rhsisnumber); |
627 { | 632 { |
628 // Convert {lhs} and {rhs} to floating point values. | 633 // Convert {lhs} and {rhs} to floating point values. |
629 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); | 634 Node* lhs_value = assembler->LoadHeapNumberValue(lhs); |
630 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | 635 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); |
631 | 636 |
632 // Perform a floating point comparison of {lhs} and {rhs}. | 637 // Perform a floating point comparison of {lhs} and {rhs}. |
633 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_true, | 638 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, |
634 &if_false); | 639 &if_notequal); |
635 } | 640 } |
636 | 641 |
637 assembler->Bind(&if_rhsisnotnumber); | 642 assembler->Bind(&if_rhsisnotnumber); |
638 assembler->Goto(&if_false); | 643 assembler->Goto(&if_notequal); |
639 } | 644 } |
640 } | 645 } |
641 | 646 |
642 assembler->Bind(&if_lhsisnotnumber); | 647 assembler->Bind(&if_lhsisnotnumber); |
643 { | 648 { |
644 // Check if {rhs} is a Smi or a HeapObject. | 649 // Check if {rhs} is a Smi or a HeapObject. |
645 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | 650 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
646 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | 651 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
647 &if_rhsisnotsmi); | 652 &if_rhsisnotsmi); |
648 | 653 |
649 assembler->Bind(&if_rhsissmi); | 654 assembler->Bind(&if_rhsissmi); |
650 assembler->Goto(&if_false); | 655 assembler->Goto(&if_notequal); |
651 | 656 |
652 assembler->Bind(&if_rhsisnotsmi); | 657 assembler->Bind(&if_rhsisnotsmi); |
653 { | 658 { |
654 // Load the instance type of {lhs}. | 659 // Load the instance type of {lhs}. |
655 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); | 660 Node* lhs_instance_type = assembler->LoadMapInstanceType(lhs_map); |
656 | 661 |
657 // Check if {lhs} is a String. | 662 // Check if {lhs} is a String. |
658 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); | 663 Label if_lhsisstring(assembler), if_lhsisnotstring(assembler); |
659 assembler->Branch(assembler->Int32LessThan( | 664 assembler->Branch(assembler->Int32LessThan( |
660 lhs_instance_type, | 665 lhs_instance_type, |
661 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), | 666 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), |
662 &if_lhsisstring, &if_lhsisnotstring); | 667 &if_lhsisstring, &if_lhsisnotstring); |
663 | 668 |
664 assembler->Bind(&if_lhsisstring); | 669 assembler->Bind(&if_lhsisstring); |
665 { | 670 { |
666 // Load the instance type of {rhs}. | 671 // Load the instance type of {rhs}. |
667 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); | 672 Node* rhs_instance_type = assembler->LoadInstanceType(rhs); |
668 | 673 |
669 // Check if {rhs} is also a String. | 674 // Check if {rhs} is also a String. |
670 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); | 675 Label if_rhsisstring(assembler), if_rhsisnotstring(assembler); |
671 assembler->Branch(assembler->Int32LessThan( | 676 assembler->Branch(assembler->Int32LessThan( |
672 rhs_instance_type, assembler->Int32Constant( | 677 rhs_instance_type, assembler->Int32Constant( |
673 FIRST_NONSTRING_TYPE)), | 678 FIRST_NONSTRING_TYPE)), |
674 &if_rhsisstring, &if_rhsisnotstring); | 679 &if_rhsisstring, &if_rhsisnotstring); |
675 | 680 |
676 assembler->Bind(&if_rhsisstring); | 681 assembler->Bind(&if_rhsisstring); |
677 { | 682 { |
678 // TODO(bmeurer): Optimize this further once the StringEqual | 683 // TODO(bmeurer): Optimize this further once the StringEqual |
679 // functionality is available in TurboFan land. | 684 // functionality is available in TurboFan land. |
680 assembler->TailCallRuntime(Runtime::kStringEqual, context, lhs, | 685 Runtime::FunctionId function_id = (mode == kStrictEqual) |
681 rhs); | 686 ? Runtime::kStringEqual |
| 687 : Runtime::kStringNotEqual; |
| 688 assembler->TailCallRuntime(function_id, context, lhs, rhs); |
682 } | 689 } |
683 | 690 |
684 assembler->Bind(&if_rhsisnotstring); | 691 assembler->Bind(&if_rhsisnotstring); |
685 assembler->Goto(&if_false); | 692 assembler->Goto(&if_notequal); |
686 } | 693 } |
687 | 694 |
688 assembler->Bind(&if_lhsisnotstring); | 695 assembler->Bind(&if_lhsisnotstring); |
689 { | 696 { |
690 // Check if {lhs} is a Simd128Value. | 697 // Check if {lhs} is a Simd128Value. |
691 Label if_lhsissimd128value(assembler), | 698 Label if_lhsissimd128value(assembler), |
692 if_lhsisnotsimd128value(assembler); | 699 if_lhsisnotsimd128value(assembler); |
693 assembler->Branch(assembler->Word32Equal( | 700 assembler->Branch(assembler->Word32Equal( |
694 lhs_instance_type, | 701 lhs_instance_type, |
695 assembler->Int32Constant(SIMD128_VALUE_TYPE)), | 702 assembler->Int32Constant(SIMD128_VALUE_TYPE)), |
696 &if_lhsissimd128value, &if_lhsisnotsimd128value); | 703 &if_lhsissimd128value, &if_lhsisnotsimd128value); |
697 | 704 |
698 assembler->Bind(&if_lhsissimd128value); | 705 assembler->Bind(&if_lhsissimd128value); |
699 { | 706 { |
700 // TODO(bmeurer): Inline the Simd128Value equality check. | 707 // TODO(bmeurer): Inline the Simd128Value equality check. |
701 assembler->TailCallRuntime(Runtime::kStrictEqual, context, lhs, | 708 Runtime::FunctionId function_id = (mode == kStrictEqual) |
702 rhs); | 709 ? Runtime::kStrictEqual |
| 710 : Runtime::kStrictNotEqual; |
| 711 assembler->TailCallRuntime(function_id, context, lhs, rhs); |
703 } | 712 } |
704 | 713 |
705 assembler->Bind(&if_lhsisnotsimd128value); | 714 assembler->Bind(&if_lhsisnotsimd128value); |
706 assembler->Goto(&if_false); | 715 assembler->Goto(&if_notequal); |
707 } | 716 } |
708 } | 717 } |
709 } | 718 } |
710 } | 719 } |
711 | 720 |
712 assembler->Bind(&if_lhsissmi); | 721 assembler->Bind(&if_lhsissmi); |
713 { | 722 { |
714 // We already know that {lhs} and {rhs} are not reference equal, and {lhs} | 723 // We already know that {lhs} and {rhs} are not reference equal, and {lhs} |
715 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a | 724 // is a Smi; so {lhs} and {rhs} can only be strictly equal if {rhs} is a |
716 // HeapNumber with an equal floating point value. | 725 // HeapNumber with an equal floating point value. |
717 | 726 |
718 // Check if {rhs} is a Smi or a HeapObject. | 727 // Check if {rhs} is a Smi or a HeapObject. |
719 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); | 728 Label if_rhsissmi(assembler), if_rhsisnotsmi(assembler); |
720 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, | 729 assembler->Branch(assembler->WordIsSmi(rhs), &if_rhsissmi, |
721 &if_rhsisnotsmi); | 730 &if_rhsisnotsmi); |
722 | 731 |
723 assembler->Bind(&if_rhsissmi); | 732 assembler->Bind(&if_rhsissmi); |
724 assembler->Goto(&if_false); | 733 assembler->Goto(&if_notequal); |
725 | 734 |
726 assembler->Bind(&if_rhsisnotsmi); | 735 assembler->Bind(&if_rhsisnotsmi); |
727 { | 736 { |
728 // Load the map of the {rhs}. | 737 // Load the map of the {rhs}. |
729 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset); | 738 Node* rhs_map = assembler->LoadObjectField(rhs, HeapObject::kMapOffset); |
730 | 739 |
731 // The {rhs} could be a HeapNumber with the same value as {lhs}. | 740 // The {rhs} could be a HeapNumber with the same value as {lhs}. |
732 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); | 741 Label if_rhsisnumber(assembler), if_rhsisnotnumber(assembler); |
733 assembler->Branch(assembler->WordEqual(rhs_map, number_map), | 742 assembler->Branch(assembler->WordEqual(rhs_map, number_map), |
734 &if_rhsisnumber, &if_rhsisnotnumber); | 743 &if_rhsisnumber, &if_rhsisnotnumber); |
735 | 744 |
736 assembler->Bind(&if_rhsisnumber); | 745 assembler->Bind(&if_rhsisnumber); |
737 { | 746 { |
738 // Convert {lhs} and {rhs} to floating point values. | 747 // Convert {lhs} and {rhs} to floating point values. |
739 Node* lhs_value = assembler->SmiToFloat64(lhs); | 748 Node* lhs_value = assembler->SmiToFloat64(lhs); |
740 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); | 749 Node* rhs_value = assembler->LoadHeapNumberValue(rhs); |
741 | 750 |
742 // Perform a floating point comparison of {lhs} and {rhs}. | 751 // Perform a floating point comparison of {lhs} and {rhs}. |
743 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_true, | 752 assembler->BranchIfFloat64Equal(lhs_value, rhs_value, &if_equal, |
744 &if_false); | 753 &if_notequal); |
745 } | 754 } |
746 | 755 |
747 assembler->Bind(&if_rhsisnotnumber); | 756 assembler->Bind(&if_rhsisnotnumber); |
748 assembler->Goto(&if_false); | 757 assembler->Goto(&if_notequal); |
749 } | 758 } |
750 } | 759 } |
751 } | 760 } |
752 | 761 |
753 assembler->Bind(&if_true); | 762 assembler->Bind(&if_equal); |
754 assembler->Return(assembler->BooleanConstant(true)); | 763 assembler->Return(assembler->BooleanConstant(mode == kStrictEqual)); |
755 | 764 |
756 assembler->Bind(&if_false); | 765 assembler->Bind(&if_notequal); |
757 assembler->Return(assembler->BooleanConstant(false)); | 766 assembler->Return(assembler->BooleanConstant(mode == kStrictNotEqual)); |
| 767 } |
| 768 |
| 769 } // namespace |
| 770 |
| 771 void StrictEqualStub::GenerateAssembly( |
| 772 compiler::CodeStubAssembler* assembler) const { |
| 773 GenerateStrictEqual(assembler, kStrictEqual); |
| 774 } |
| 775 |
| 776 void StrictNotEqualStub::GenerateAssembly( |
| 777 compiler::CodeStubAssembler* assembler) const { |
| 778 GenerateStrictEqual(assembler, kStrictNotEqual); |
758 } | 779 } |
759 | 780 |
760 void ToBooleanStub::GenerateAssembly( | 781 void ToBooleanStub::GenerateAssembly( |
761 compiler::CodeStubAssembler* assembler) const { | 782 compiler::CodeStubAssembler* assembler) const { |
762 typedef compiler::Node Node; | 783 typedef compiler::Node Node; |
763 typedef compiler::CodeStubAssembler::Label Label; | 784 typedef compiler::CodeStubAssembler::Label Label; |
764 | 785 |
765 Node* value = assembler->Parameter(0); | 786 Node* value = assembler->Parameter(0); |
766 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); | 787 Label if_valueissmi(assembler), if_valueisnotsmi(assembler); |
767 | 788 |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1325 if (type->Is(Type::UntaggedPointer())) { | 1346 if (type->Is(Type::UntaggedPointer())) { |
1326 return Representation::External(); | 1347 return Representation::External(); |
1327 } | 1348 } |
1328 | 1349 |
1329 DCHECK(!type->Is(Type::Untagged())); | 1350 DCHECK(!type->Is(Type::Untagged())); |
1330 return Representation::Tagged(); | 1351 return Representation::Tagged(); |
1331 } | 1352 } |
1332 | 1353 |
1333 } // namespace internal | 1354 } // namespace internal |
1334 } // namespace v8 | 1355 } // namespace v8 |
OLD | NEW |