| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 Isolate* isolate, | 148 Isolate* isolate, |
| 149 CodeStubInterfaceDescriptor* descriptor) { | 149 CodeStubInterfaceDescriptor* descriptor) { |
| 150 static Register registers[] = { rax, rbx }; | 150 static Register registers[] = { rax, rbx }; |
| 151 descriptor->register_param_count_ = 2; | 151 descriptor->register_param_count_ = 2; |
| 152 descriptor->register_params_ = registers; | 152 descriptor->register_params_ = registers; |
| 153 descriptor->deoptimization_handler_ = | 153 descriptor->deoptimization_handler_ = |
| 154 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry; | 154 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry; |
| 155 } | 155 } |
| 156 | 156 |
| 157 | 157 |
| 158 void BinaryOpStub::InitializeInterfaceDescriptor( |
| 159 Isolate* isolate, |
| 160 CodeStubInterfaceDescriptor* descriptor) { |
| 161 static Register registers[] = { rdx, rax }; |
| 162 descriptor->register_param_count_ = 2; |
| 163 descriptor->register_params_ = registers; |
| 164 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss); |
| 165 descriptor->SetMissHandler( |
| 166 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate)); |
| 167 } |
| 168 |
| 169 |
| 158 static void InitializeArrayConstructorDescriptor( | 170 static void InitializeArrayConstructorDescriptor( |
| 159 Isolate* isolate, | 171 Isolate* isolate, |
| 160 CodeStubInterfaceDescriptor* descriptor, | 172 CodeStubInterfaceDescriptor* descriptor, |
| 161 int constant_stack_parameter_count) { | 173 int constant_stack_parameter_count) { |
| 162 // register state | 174 // register state |
| 163 // rax -- number of arguments | 175 // rax -- number of arguments |
| 164 // rdi -- function | 176 // rdi -- function |
| 165 // rbx -- type info cell with elements kind | 177 // rbx -- type info cell with elements kind |
| 166 static Register registers[] = { rdi, rbx }; | 178 static Register registers[] = { rdi, rbx }; |
| 167 descriptor->register_param_count_ = 2; | 179 descriptor->register_param_count_ = 2; |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 class FloatingPointHelper : public AllStatic { | 452 class FloatingPointHelper : public AllStatic { |
| 441 public: | 453 public: |
| 442 enum ConvertUndefined { | 454 enum ConvertUndefined { |
| 443 CONVERT_UNDEFINED_TO_ZERO, | 455 CONVERT_UNDEFINED_TO_ZERO, |
| 444 BAILOUT_ON_UNDEFINED | 456 BAILOUT_ON_UNDEFINED |
| 445 }; | 457 }; |
| 446 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. | 458 // Load the operands from rdx and rax into xmm0 and xmm1, as doubles. |
| 447 // If the operands are not both numbers, jump to not_numbers. | 459 // If the operands are not both numbers, jump to not_numbers. |
| 448 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. | 460 // Leaves rdx and rax unchanged. SmiOperands assumes both are smis. |
| 449 // NumberOperands assumes both are smis or heap numbers. | 461 // NumberOperands assumes both are smis or heap numbers. |
| 450 static void LoadSSE2SmiOperands(MacroAssembler* masm); | |
| 451 static void LoadSSE2UnknownOperands(MacroAssembler* masm, | 462 static void LoadSSE2UnknownOperands(MacroAssembler* masm, |
| 452 Label* not_numbers); | 463 Label* not_numbers); |
| 453 | |
| 454 // Takes the operands in rdx and rax and loads them as integers in rax | |
| 455 // and rcx. | |
| 456 static void LoadAsIntegers(MacroAssembler* masm, | |
| 457 Label* operand_conversion_failure, | |
| 458 Register heap_number_map); | |
| 459 | |
| 460 // Tries to convert two values to smis losslessly. | |
| 461 // This fails if either argument is not a Smi nor a HeapNumber, | |
| 462 // or if it's a HeapNumber with a value that can't be converted | |
| 463 // losslessly to a Smi. In that case, control transitions to the | |
| 464 // on_not_smis label. | |
| 465 // On success, either control goes to the on_success label (if one is | |
| 466 // provided), or it falls through at the end of the code (if on_success | |
| 467 // is NULL). | |
| 468 // On success, both first and second holds Smi tagged values. | |
| 469 // One of first or second must be non-Smi when entering. | |
| 470 static void NumbersToSmis(MacroAssembler* masm, | |
| 471 Register first, | |
| 472 Register second, | |
| 473 Register scratch1, | |
| 474 Register scratch2, | |
| 475 Register scratch3, | |
| 476 Label* on_success, | |
| 477 Label* on_not_smis, | |
| 478 ConvertUndefined convert_undefined); | |
| 479 }; | 464 }; |
| 480 | 465 |
| 481 | 466 |
| 482 void DoubleToIStub::Generate(MacroAssembler* masm) { | 467 void DoubleToIStub::Generate(MacroAssembler* masm) { |
| 483 Register input_reg = this->source(); | 468 Register input_reg = this->source(); |
| 484 Register final_result_reg = this->destination(); | 469 Register final_result_reg = this->destination(); |
| 485 ASSERT(is_truncating()); | 470 ASSERT(is_truncating()); |
| 486 | 471 |
| 487 Label check_negative, process_64_bits, done; | 472 Label check_negative, process_64_bits, done; |
| 488 | 473 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 556 if (!final_result_reg.is(result_reg)) { | 541 if (!final_result_reg.is(result_reg)) { |
| 557 ASSERT(final_result_reg.is(rcx)); | 542 ASSERT(final_result_reg.is(rcx)); |
| 558 __ movl(final_result_reg, result_reg); | 543 __ movl(final_result_reg, result_reg); |
| 559 } | 544 } |
| 560 __ pop(save_reg); | 545 __ pop(save_reg); |
| 561 __ pop(scratch1); | 546 __ pop(scratch1); |
| 562 __ ret(0); | 547 __ ret(0); |
| 563 } | 548 } |
| 564 | 549 |
| 565 | 550 |
| 566 void BinaryOpStub::Initialize() {} | |
| 567 | |
| 568 | |
| 569 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | |
| 570 __ PopReturnAddressTo(rcx); | |
| 571 __ push(rdx); | |
| 572 __ push(rax); | |
| 573 // Left and right arguments are now on top. | |
| 574 __ Push(Smi::FromInt(MinorKey())); | |
| 575 | |
| 576 __ PushReturnAddressFrom(rcx); | |
| 577 | |
| 578 // Patch the caller to an appropriate specialized stub and return the | |
| 579 // operation result to the caller of the stub. | |
| 580 __ TailCallExternalReference( | |
| 581 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), | |
| 582 masm->isolate()), | |
| 583 3, | |
| 584 1); | |
| 585 } | |
| 586 | |
| 587 | |
| 588 static void BinaryOpStub_GenerateSmiCode( | |
| 589 MacroAssembler* masm, | |
| 590 Label* slow, | |
| 591 BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, | |
| 592 Token::Value op) { | |
| 593 | |
| 594 // Arguments to BinaryOpStub are in rdx and rax. | |
| 595 const Register left = rdx; | |
| 596 const Register right = rax; | |
| 597 | |
| 598 // We only generate heapnumber answers for overflowing calculations | |
| 599 // for the four basic arithmetic operations and logical right shift by 0. | |
| 600 bool generate_inline_heapnumber_results = | |
| 601 (allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS) && | |
| 602 (op == Token::ADD || op == Token::SUB || | |
| 603 op == Token::MUL || op == Token::DIV || op == Token::SHR); | |
| 604 | |
| 605 // Smi check of both operands. If op is BIT_OR, the check is delayed | |
| 606 // until after the OR operation. | |
| 607 Label not_smis; | |
| 608 Label use_fp_on_smis; | |
| 609 Label fail; | |
| 610 | |
| 611 if (op != Token::BIT_OR) { | |
| 612 Comment smi_check_comment(masm, "-- Smi check arguments"); | |
| 613 __ JumpIfNotBothSmi(left, right, ¬_smis); | |
| 614 } | |
| 615 | |
| 616 Label smi_values; | |
| 617 __ bind(&smi_values); | |
| 618 // Perform the operation. | |
| 619 Comment perform_smi(masm, "-- Perform smi operation"); | |
| 620 switch (op) { | |
| 621 case Token::ADD: | |
| 622 ASSERT(right.is(rax)); | |
| 623 __ SmiAdd(right, right, left, &use_fp_on_smis); // ADD is commutative. | |
| 624 break; | |
| 625 | |
| 626 case Token::SUB: | |
| 627 __ SmiSub(left, left, right, &use_fp_on_smis); | |
| 628 __ movq(rax, left); | |
| 629 break; | |
| 630 | |
| 631 case Token::MUL: | |
| 632 ASSERT(right.is(rax)); | |
| 633 __ SmiMul(right, right, left, &use_fp_on_smis); // MUL is commutative. | |
| 634 break; | |
| 635 | |
| 636 case Token::DIV: | |
| 637 // SmiDiv will not accept left in rdx or right in rax. | |
| 638 __ movq(rbx, rax); | |
| 639 __ movq(rcx, rdx); | |
| 640 __ SmiDiv(rax, rcx, rbx, &use_fp_on_smis); | |
| 641 break; | |
| 642 | |
| 643 case Token::MOD: | |
| 644 // SmiMod will not accept left in rdx or right in rax. | |
| 645 __ movq(rbx, rax); | |
| 646 __ movq(rcx, rdx); | |
| 647 __ SmiMod(rax, rcx, rbx, &use_fp_on_smis); | |
| 648 break; | |
| 649 | |
| 650 case Token::BIT_OR: { | |
| 651 ASSERT(right.is(rax)); | |
| 652 __ SmiOrIfSmis(right, right, left, ¬_smis); // BIT_OR is commutative. | |
| 653 break; | |
| 654 } | |
| 655 case Token::BIT_XOR: | |
| 656 ASSERT(right.is(rax)); | |
| 657 __ SmiXor(right, right, left); // BIT_XOR is commutative. | |
| 658 break; | |
| 659 | |
| 660 case Token::BIT_AND: | |
| 661 ASSERT(right.is(rax)); | |
| 662 __ SmiAnd(right, right, left); // BIT_AND is commutative. | |
| 663 break; | |
| 664 | |
| 665 case Token::SHL: | |
| 666 __ SmiShiftLeft(left, left, right); | |
| 667 __ movq(rax, left); | |
| 668 break; | |
| 669 | |
| 670 case Token::SAR: | |
| 671 __ SmiShiftArithmeticRight(left, left, right); | |
| 672 __ movq(rax, left); | |
| 673 break; | |
| 674 | |
| 675 case Token::SHR: | |
| 676 __ SmiShiftLogicalRight(left, left, right, &use_fp_on_smis); | |
| 677 __ movq(rax, left); | |
| 678 break; | |
| 679 | |
| 680 default: | |
| 681 UNREACHABLE(); | |
| 682 } | |
| 683 | |
| 684 // 5. Emit return of result in rax. Some operations have registers pushed. | |
| 685 __ ret(0); | |
| 686 | |
| 687 if (use_fp_on_smis.is_linked()) { | |
| 688 // 6. For some operations emit inline code to perform floating point | |
| 689 // operations on known smis (e.g., if the result of the operation | |
| 690 // overflowed the smi range). | |
| 691 __ bind(&use_fp_on_smis); | |
| 692 if (op == Token::DIV || op == Token::MOD) { | |
| 693 // Restore left and right to rdx and rax. | |
| 694 __ movq(rdx, rcx); | |
| 695 __ movq(rax, rbx); | |
| 696 } | |
| 697 | |
| 698 if (generate_inline_heapnumber_results) { | |
| 699 __ AllocateHeapNumber(rcx, rbx, slow); | |
| 700 Comment perform_float(masm, "-- Perform float operation on smis"); | |
| 701 if (op == Token::SHR) { | |
| 702 __ SmiToInteger32(left, left); | |
| 703 __ cvtqsi2sd(xmm0, left); | |
| 704 } else { | |
| 705 FloatingPointHelper::LoadSSE2SmiOperands(masm); | |
| 706 switch (op) { | |
| 707 case Token::ADD: __ addsd(xmm0, xmm1); break; | |
| 708 case Token::SUB: __ subsd(xmm0, xmm1); break; | |
| 709 case Token::MUL: __ mulsd(xmm0, xmm1); break; | |
| 710 case Token::DIV: __ divsd(xmm0, xmm1); break; | |
| 711 default: UNREACHABLE(); | |
| 712 } | |
| 713 } | |
| 714 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); | |
| 715 __ movq(rax, rcx); | |
| 716 __ ret(0); | |
| 717 } else { | |
| 718 __ jmp(&fail); | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 // 7. Non-smi operands reach the end of the code generated by | |
| 723 // GenerateSmiCode, and fall through to subsequent code, | |
| 724 // with the operands in rdx and rax. | |
| 725 // But first we check if non-smi values are HeapNumbers holding | |
| 726 // values that could be smi. | |
| 727 __ bind(¬_smis); | |
| 728 Comment done_comment(masm, "-- Enter non-smi code"); | |
| 729 FloatingPointHelper::ConvertUndefined convert_undefined = | |
| 730 FloatingPointHelper::BAILOUT_ON_UNDEFINED; | |
| 731 // This list must be in sync with BinaryOpPatch() behavior in ic.cc. | |
| 732 if (op == Token::BIT_AND || | |
| 733 op == Token::BIT_OR || | |
| 734 op == Token::BIT_XOR || | |
| 735 op == Token::SAR || | |
| 736 op == Token::SHL || | |
| 737 op == Token::SHR) { | |
| 738 convert_undefined = FloatingPointHelper::CONVERT_UNDEFINED_TO_ZERO; | |
| 739 } | |
| 740 FloatingPointHelper::NumbersToSmis(masm, left, right, rbx, rdi, rcx, | |
| 741 &smi_values, &fail, convert_undefined); | |
| 742 __ jmp(&smi_values); | |
| 743 __ bind(&fail); | |
| 744 } | |
| 745 | |
| 746 | |
| 747 static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | |
| 748 Label* alloc_failure, | |
| 749 OverwriteMode mode); | |
| 750 | |
| 751 | |
| 752 static void BinaryOpStub_GenerateFloatingPointCode(MacroAssembler* masm, | |
| 753 Label* allocation_failure, | |
| 754 Label* non_numeric_failure, | |
| 755 Token::Value op, | |
| 756 OverwriteMode mode) { | |
| 757 switch (op) { | |
| 758 case Token::ADD: | |
| 759 case Token::SUB: | |
| 760 case Token::MUL: | |
| 761 case Token::DIV: { | |
| 762 FloatingPointHelper::LoadSSE2UnknownOperands(masm, non_numeric_failure); | |
| 763 | |
| 764 switch (op) { | |
| 765 case Token::ADD: __ addsd(xmm0, xmm1); break; | |
| 766 case Token::SUB: __ subsd(xmm0, xmm1); break; | |
| 767 case Token::MUL: __ mulsd(xmm0, xmm1); break; | |
| 768 case Token::DIV: __ divsd(xmm0, xmm1); break; | |
| 769 default: UNREACHABLE(); | |
| 770 } | |
| 771 BinaryOpStub_GenerateHeapResultAllocation( | |
| 772 masm, allocation_failure, mode); | |
| 773 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); | |
| 774 __ ret(0); | |
| 775 break; | |
| 776 } | |
| 777 case Token::MOD: { | |
| 778 // For MOD we jump to the allocation_failure label, to call runtime. | |
| 779 __ jmp(allocation_failure); | |
| 780 break; | |
| 781 } | |
| 782 case Token::BIT_OR: | |
| 783 case Token::BIT_AND: | |
| 784 case Token::BIT_XOR: | |
| 785 case Token::SAR: | |
| 786 case Token::SHL: | |
| 787 case Token::SHR: { | |
| 788 Label non_smi_shr_result; | |
| 789 Register heap_number_map = r9; | |
| 790 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
| 791 FloatingPointHelper::LoadAsIntegers(masm, non_numeric_failure, | |
| 792 heap_number_map); | |
| 793 switch (op) { | |
| 794 case Token::BIT_OR: __ orl(rax, rcx); break; | |
| 795 case Token::BIT_AND: __ andl(rax, rcx); break; | |
| 796 case Token::BIT_XOR: __ xorl(rax, rcx); break; | |
| 797 case Token::SAR: __ sarl_cl(rax); break; | |
| 798 case Token::SHL: __ shll_cl(rax); break; | |
| 799 case Token::SHR: { | |
| 800 __ shrl_cl(rax); | |
| 801 // Check if result is negative. This can only happen for a shift | |
| 802 // by zero. | |
| 803 __ testl(rax, rax); | |
| 804 __ j(negative, &non_smi_shr_result); | |
| 805 break; | |
| 806 } | |
| 807 default: UNREACHABLE(); | |
| 808 } | |
| 809 STATIC_ASSERT(kSmiValueSize == 32); | |
| 810 // Tag smi result and return. | |
| 811 __ Integer32ToSmi(rax, rax); | |
| 812 __ Ret(); | |
| 813 | |
| 814 // Logical shift right can produce an unsigned int32 that is not | |
| 815 // an int32, and so is not in the smi range. Allocate a heap number | |
| 816 // in that case. | |
| 817 if (op == Token::SHR) { | |
| 818 __ bind(&non_smi_shr_result); | |
| 819 Label allocation_failed; | |
| 820 __ movl(rbx, rax); // rbx holds result value (uint32 value as int64). | |
| 821 // Allocate heap number in new space. | |
| 822 // Not using AllocateHeapNumber macro in order to reuse | |
| 823 // already loaded heap_number_map. | |
| 824 __ Allocate(HeapNumber::kSize, rax, rdx, no_reg, &allocation_failed, | |
| 825 TAG_OBJECT); | |
| 826 // Set the map. | |
| 827 __ AssertRootValue(heap_number_map, | |
| 828 Heap::kHeapNumberMapRootIndex, | |
| 829 kHeapNumberMapRegisterClobbered); | |
| 830 __ movq(FieldOperand(rax, HeapObject::kMapOffset), | |
| 831 heap_number_map); | |
| 832 __ cvtqsi2sd(xmm0, rbx); | |
| 833 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm0); | |
| 834 __ Ret(); | |
| 835 | |
| 836 __ bind(&allocation_failed); | |
| 837 // We need tagged values in rdx and rax for the following code, | |
| 838 // not int32 in rax and rcx. | |
| 839 __ Integer32ToSmi(rax, rcx); | |
| 840 __ Integer32ToSmi(rdx, rbx); | |
| 841 __ jmp(allocation_failure); | |
| 842 } | |
| 843 break; | |
| 844 } | |
| 845 default: UNREACHABLE(); break; | |
| 846 } | |
| 847 // No fall-through from this generated code. | |
| 848 if (FLAG_debug_code) { | |
| 849 __ Abort(kUnexpectedFallThroughInBinaryStubGenerateFloatingPointCode); | |
| 850 } | |
| 851 } | |
| 852 | |
| 853 | |
| 854 static void BinaryOpStub_GenerateRegisterArgsPushUnderReturn( | |
| 855 MacroAssembler* masm) { | |
| 856 // Push arguments, but ensure they are under the return address | |
| 857 // for a tail call. | |
| 858 __ PopReturnAddressTo(rcx); | |
| 859 __ push(rdx); | |
| 860 __ push(rax); | |
| 861 __ PushReturnAddressFrom(rcx); | |
| 862 } | |
| 863 | |
| 864 | |
| 865 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { | |
| 866 ASSERT(op_ == Token::ADD); | |
| 867 Label left_not_string, call_runtime; | |
| 868 | |
| 869 // Registers containing left and right operands respectively. | |
| 870 Register left = rdx; | |
| 871 Register right = rax; | |
| 872 | |
| 873 // Test if left operand is a string. | |
| 874 __ JumpIfSmi(left, &left_not_string, Label::kNear); | |
| 875 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | |
| 876 __ j(above_equal, &left_not_string, Label::kNear); | |
| 877 StringAddStub string_add_left_stub( | |
| 878 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); | |
| 879 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | |
| 880 __ TailCallStub(&string_add_left_stub); | |
| 881 | |
| 882 // Left operand is not a string, test right. | |
| 883 __ bind(&left_not_string); | |
| 884 __ JumpIfSmi(right, &call_runtime, Label::kNear); | |
| 885 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | |
| 886 __ j(above_equal, &call_runtime, Label::kNear); | |
| 887 | |
| 888 StringAddStub string_add_right_stub( | |
| 889 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); | |
| 890 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | |
| 891 __ TailCallStub(&string_add_right_stub); | |
| 892 | |
| 893 // Neither argument is a string. | |
| 894 __ bind(&call_runtime); | |
| 895 } | |
| 896 | |
| 897 | |
| 898 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | |
| 899 Label right_arg_changed, call_runtime; | |
| 900 | |
| 901 if (op_ == Token::MOD && encoded_right_arg_.has_value) { | |
| 902 // It is guaranteed that the value will fit into a Smi, because if it | |
| 903 // didn't, we wouldn't be here, see BinaryOp_Patch. | |
| 904 __ Cmp(rax, Smi::FromInt(fixed_right_arg_value())); | |
| 905 __ j(not_equal, &right_arg_changed); | |
| 906 } | |
| 907 | |
| 908 if (result_type_ == BinaryOpIC::UNINITIALIZED || | |
| 909 result_type_ == BinaryOpIC::SMI) { | |
| 910 // Only allow smi results. | |
| 911 BinaryOpStub_GenerateSmiCode(masm, NULL, NO_HEAPNUMBER_RESULTS, op_); | |
| 912 } else { | |
| 913 // Allow heap number result and don't make a transition if a heap number | |
| 914 // cannot be allocated. | |
| 915 BinaryOpStub_GenerateSmiCode( | |
| 916 masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); | |
| 917 } | |
| 918 | |
| 919 // Code falls through if the result is not returned as either a smi or heap | |
| 920 // number. | |
| 921 __ bind(&right_arg_changed); | |
| 922 GenerateTypeTransition(masm); | |
| 923 | |
| 924 if (call_runtime.is_linked()) { | |
| 925 __ bind(&call_runtime); | |
| 926 { | |
| 927 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 928 GenerateRegisterArgsPush(masm); | |
| 929 GenerateCallRuntime(masm); | |
| 930 } | |
| 931 __ Ret(); | |
| 932 } | |
| 933 } | |
| 934 | |
| 935 | |
| 936 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | |
| 937 // The int32 case is identical to the Smi case. We avoid creating this | |
| 938 // ic state on x64. | |
| 939 UNREACHABLE(); | |
| 940 } | |
| 941 | |
| 942 | |
| 943 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { | |
| 944 Label call_runtime; | |
| 945 ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); | |
| 946 ASSERT(op_ == Token::ADD); | |
| 947 // If both arguments are strings, call the string add stub. | |
| 948 // Otherwise, do a transition. | |
| 949 | |
| 950 // Registers containing left and right operands respectively. | |
| 951 Register left = rdx; | |
| 952 Register right = rax; | |
| 953 | |
| 954 // Test if left operand is a string. | |
| 955 __ JumpIfSmi(left, &call_runtime); | |
| 956 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, rcx); | |
| 957 __ j(above_equal, &call_runtime); | |
| 958 | |
| 959 // Test if right operand is a string. | |
| 960 __ JumpIfSmi(right, &call_runtime); | |
| 961 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, rcx); | |
| 962 __ j(above_equal, &call_runtime); | |
| 963 | |
| 964 StringAddStub string_add_stub( | |
| 965 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); | |
| 966 BinaryOpStub_GenerateRegisterArgsPushUnderReturn(masm); | |
| 967 __ TailCallStub(&string_add_stub); | |
| 968 | |
| 969 __ bind(&call_runtime); | |
| 970 GenerateTypeTransition(masm); | |
| 971 } | |
| 972 | |
| 973 | |
| 974 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { | |
| 975 Label call_runtime; | |
| 976 | |
| 977 if (op_ == Token::ADD) { | |
| 978 // Handle string addition here, because it is the only operation | |
| 979 // that does not do a ToNumber conversion on the operands. | |
| 980 GenerateAddStrings(masm); | |
| 981 } | |
| 982 | |
| 983 // Convert oddball arguments to numbers. | |
| 984 Label check, done; | |
| 985 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | |
| 986 __ j(not_equal, &check, Label::kNear); | |
| 987 if (Token::IsBitOp(op_)) { | |
| 988 __ xor_(rdx, rdx); | |
| 989 } else { | |
| 990 __ LoadRoot(rdx, Heap::kNanValueRootIndex); | |
| 991 } | |
| 992 __ jmp(&done, Label::kNear); | |
| 993 __ bind(&check); | |
| 994 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | |
| 995 __ j(not_equal, &done, Label::kNear); | |
| 996 if (Token::IsBitOp(op_)) { | |
| 997 __ xor_(rax, rax); | |
| 998 } else { | |
| 999 __ LoadRoot(rax, Heap::kNanValueRootIndex); | |
| 1000 } | |
| 1001 __ bind(&done); | |
| 1002 | |
| 1003 GenerateNumberStub(masm); | |
| 1004 } | |
| 1005 | |
| 1006 | |
| 1007 static void BinaryOpStub_CheckSmiInput(MacroAssembler* masm, | |
| 1008 Register input, | |
| 1009 Label* fail) { | |
| 1010 Label ok; | |
| 1011 __ JumpIfSmi(input, &ok, Label::kNear); | |
| 1012 Register heap_number_map = r8; | |
| 1013 Register scratch1 = r9; | |
| 1014 Register scratch2 = r10; | |
| 1015 // HeapNumbers containing 32bit integer values are also allowed. | |
| 1016 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
| 1017 __ cmpq(FieldOperand(input, HeapObject::kMapOffset), heap_number_map); | |
| 1018 __ j(not_equal, fail); | |
| 1019 __ movsd(xmm0, FieldOperand(input, HeapNumber::kValueOffset)); | |
| 1020 // Convert, convert back, and compare the two doubles' bits. | |
| 1021 __ cvttsd2siq(scratch2, xmm0); | |
| 1022 __ Cvtlsi2sd(xmm1, scratch2); | |
| 1023 __ movq(scratch1, xmm0); | |
| 1024 __ movq(scratch2, xmm1); | |
| 1025 __ cmpq(scratch1, scratch2); | |
| 1026 __ j(not_equal, fail); | |
| 1027 __ bind(&ok); | |
| 1028 } | |
| 1029 | |
| 1030 | |
| 1031 void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) { | |
| 1032 Label gc_required, not_number; | |
| 1033 | |
| 1034 // It could be that only SMIs have been seen at either the left | |
| 1035 // or the right operand. For precise type feedback, patch the IC | |
| 1036 // again if this changes. | |
| 1037 if (left_type_ == BinaryOpIC::SMI) { | |
| 1038 BinaryOpStub_CheckSmiInput(masm, rdx, ¬_number); | |
| 1039 } | |
| 1040 if (right_type_ == BinaryOpIC::SMI) { | |
| 1041 BinaryOpStub_CheckSmiInput(masm, rax, ¬_number); | |
| 1042 } | |
| 1043 | |
| 1044 BinaryOpStub_GenerateFloatingPointCode( | |
| 1045 masm, &gc_required, ¬_number, op_, mode_); | |
| 1046 | |
| 1047 __ bind(¬_number); | |
| 1048 GenerateTypeTransition(masm); | |
| 1049 | |
| 1050 __ bind(&gc_required); | |
| 1051 { | |
| 1052 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1053 GenerateRegisterArgsPush(masm); | |
| 1054 GenerateCallRuntime(masm); | |
| 1055 } | |
| 1056 __ Ret(); | |
| 1057 } | |
| 1058 | |
| 1059 | |
| 1060 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { | |
| 1061 Label call_runtime, call_string_add_or_runtime; | |
| 1062 | |
| 1063 BinaryOpStub_GenerateSmiCode( | |
| 1064 masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); | |
| 1065 | |
| 1066 BinaryOpStub_GenerateFloatingPointCode( | |
| 1067 masm, &call_runtime, &call_string_add_or_runtime, op_, mode_); | |
| 1068 | |
| 1069 __ bind(&call_string_add_or_runtime); | |
| 1070 if (op_ == Token::ADD) { | |
| 1071 GenerateAddStrings(masm); | |
| 1072 } | |
| 1073 | |
| 1074 __ bind(&call_runtime); | |
| 1075 { | |
| 1076 FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1077 GenerateRegisterArgsPush(masm); | |
| 1078 GenerateCallRuntime(masm); | |
| 1079 } | |
| 1080 __ Ret(); | |
| 1081 } | |
| 1082 | |
| 1083 | |
| 1084 static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | |
| 1085 Label* alloc_failure, | |
| 1086 OverwriteMode mode) { | |
| 1087 Label skip_allocation; | |
| 1088 switch (mode) { | |
| 1089 case OVERWRITE_LEFT: { | |
| 1090 // If the argument in rdx is already an object, we skip the | |
| 1091 // allocation of a heap number. | |
| 1092 __ JumpIfNotSmi(rdx, &skip_allocation); | |
| 1093 // Allocate a heap number for the result. Keep rax and rdx intact | |
| 1094 // for the possible runtime call. | |
| 1095 __ AllocateHeapNumber(rbx, rcx, alloc_failure); | |
| 1096 // Now rdx can be overwritten losing one of the arguments as we are | |
| 1097 // now done and will not need it any more. | |
| 1098 __ movq(rdx, rbx); | |
| 1099 __ bind(&skip_allocation); | |
| 1100 // Use object in rdx as a result holder | |
| 1101 __ movq(rax, rdx); | |
| 1102 break; | |
| 1103 } | |
| 1104 case OVERWRITE_RIGHT: | |
| 1105 // If the argument in rax is already an object, we skip the | |
| 1106 // allocation of a heap number. | |
| 1107 __ JumpIfNotSmi(rax, &skip_allocation); | |
| 1108 // Fall through! | |
| 1109 case NO_OVERWRITE: | |
| 1110 // Allocate a heap number for the result. Keep rax and rdx intact | |
| 1111 // for the possible runtime call. | |
| 1112 __ AllocateHeapNumber(rbx, rcx, alloc_failure); | |
| 1113 // Now rax can be overwritten losing one of the arguments as we are | |
| 1114 // now done and will not need it any more. | |
| 1115 __ movq(rax, rbx); | |
| 1116 __ bind(&skip_allocation); | |
| 1117 break; | |
| 1118 default: UNREACHABLE(); | |
| 1119 } | |
| 1120 } | |
| 1121 | |
| 1122 | |
| 1123 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
| 1124 __ push(rdx); | |
| 1125 __ push(rax); | |
| 1126 } | |
| 1127 | |
| 1128 | |
| 1129 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 551 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 1130 // TAGGED case: | 552 // TAGGED case: |
| 1131 // Input: | 553 // Input: |
| 1132 // rsp[8] : argument (should be number). | 554 // rsp[8] : argument (should be number). |
| 1133 // rsp[0] : return address. | 555 // rsp[0] : return address. |
| 1134 // Output: | 556 // Output: |
| 1135 // rax: tagged double result. | 557 // rax: tagged double result. |
| 1136 // UNTAGGED case: | 558 // UNTAGGED case: |
| 1137 // Input:: | 559 // Input:: |
| 1138 // rsp[0] : return address. | 560 // rsp[0] : return address. |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1425 __ bind(&done); | 847 __ bind(&done); |
| 1426 } else { | 848 } else { |
| 1427 ASSERT(type == TranscendentalCache::LOG); | 849 ASSERT(type == TranscendentalCache::LOG); |
| 1428 __ fldln2(); | 850 __ fldln2(); |
| 1429 __ fxch(); | 851 __ fxch(); |
| 1430 __ fyl2x(); | 852 __ fyl2x(); |
| 1431 } | 853 } |
| 1432 } | 854 } |
| 1433 | 855 |
| 1434 | 856 |
| 1435 // Input: rdx, rax are the left and right objects of a bit op. | |
| 1436 // Output: rax, rcx are left and right integers for a bit op. | |
| 1437 // Jump to conversion_failure: rdx and rax are unchanged. | |
| 1438 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | |
| 1439 Label* conversion_failure, | |
| 1440 Register heap_number_map) { | |
| 1441 // Check float operands. | |
| 1442 Label arg1_is_object, check_undefined_arg1; | |
| 1443 Label arg2_is_object, check_undefined_arg2; | |
| 1444 Label load_arg2, done; | |
| 1445 | |
| 1446 __ JumpIfNotSmi(rdx, &arg1_is_object); | |
| 1447 __ SmiToInteger32(r8, rdx); | |
| 1448 __ jmp(&load_arg2); | |
| 1449 | |
| 1450 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | |
| 1451 __ bind(&check_undefined_arg1); | |
| 1452 __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex); | |
| 1453 __ j(not_equal, conversion_failure); | |
| 1454 __ Set(r8, 0); | |
| 1455 __ jmp(&load_arg2); | |
| 1456 | |
| 1457 __ bind(&arg1_is_object); | |
| 1458 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), heap_number_map); | |
| 1459 __ j(not_equal, &check_undefined_arg1); | |
| 1460 // Get the untagged integer version of the rdx heap number in r8. | |
| 1461 __ TruncateHeapNumberToI(r8, rdx); | |
| 1462 | |
| 1463 // Here r8 has the untagged integer, rax has a Smi or a heap number. | |
| 1464 __ bind(&load_arg2); | |
| 1465 // Test if arg2 is a Smi. | |
| 1466 __ JumpIfNotSmi(rax, &arg2_is_object); | |
| 1467 __ SmiToInteger32(rcx, rax); | |
| 1468 __ jmp(&done); | |
| 1469 | |
| 1470 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | |
| 1471 __ bind(&check_undefined_arg2); | |
| 1472 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | |
| 1473 __ j(not_equal, conversion_failure); | |
| 1474 __ Set(rcx, 0); | |
| 1475 __ jmp(&done); | |
| 1476 | |
| 1477 __ bind(&arg2_is_object); | |
| 1478 __ cmpq(FieldOperand(rax, HeapObject::kMapOffset), heap_number_map); | |
| 1479 __ j(not_equal, &check_undefined_arg2); | |
| 1480 // Get the untagged integer version of the rax heap number in rcx. | |
| 1481 __ TruncateHeapNumberToI(rcx, rax); | |
| 1482 | |
| 1483 __ bind(&done); | |
| 1484 __ movl(rax, r8); | |
| 1485 } | |
| 1486 | |
| 1487 | |
| 1488 void FloatingPointHelper::LoadSSE2SmiOperands(MacroAssembler* masm) { | |
| 1489 __ SmiToInteger32(kScratchRegister, rdx); | |
| 1490 __ Cvtlsi2sd(xmm0, kScratchRegister); | |
| 1491 __ SmiToInteger32(kScratchRegister, rax); | |
| 1492 __ Cvtlsi2sd(xmm1, kScratchRegister); | |
| 1493 } | |
| 1494 | |
| 1495 | |
| 1496 void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, | 857 void FloatingPointHelper::LoadSSE2UnknownOperands(MacroAssembler* masm, |
| 1497 Label* not_numbers) { | 858 Label* not_numbers) { |
| 1498 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done; | 859 Label load_smi_rdx, load_nonsmi_rax, load_smi_rax, load_float_rax, done; |
| 1499 // Load operand in rdx into xmm0, or branch to not_numbers. | 860 // Load operand in rdx into xmm0, or branch to not_numbers. |
| 1500 __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex); | 861 __ LoadRoot(rcx, Heap::kHeapNumberMapRootIndex); |
| 1501 __ JumpIfSmi(rdx, &load_smi_rdx); | 862 __ JumpIfSmi(rdx, &load_smi_rdx); |
| 1502 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx); | 863 __ cmpq(FieldOperand(rdx, HeapObject::kMapOffset), rcx); |
| 1503 __ j(not_equal, not_numbers); // Argument in rdx is not a number. | 864 __ j(not_equal, not_numbers); // Argument in rdx is not a number. |
| 1504 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); | 865 __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset)); |
| 1505 // Load operand in rax into xmm1, or branch to not_numbers. | 866 // Load operand in rax into xmm1, or branch to not_numbers. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1516 __ Cvtlsi2sd(xmm0, kScratchRegister); | 877 __ Cvtlsi2sd(xmm0, kScratchRegister); |
| 1517 __ JumpIfNotSmi(rax, &load_nonsmi_rax); | 878 __ JumpIfNotSmi(rax, &load_nonsmi_rax); |
| 1518 | 879 |
| 1519 __ bind(&load_smi_rax); | 880 __ bind(&load_smi_rax); |
| 1520 __ SmiToInteger32(kScratchRegister, rax); | 881 __ SmiToInteger32(kScratchRegister, rax); |
| 1521 __ Cvtlsi2sd(xmm1, kScratchRegister); | 882 __ Cvtlsi2sd(xmm1, kScratchRegister); |
| 1522 __ bind(&done); | 883 __ bind(&done); |
| 1523 } | 884 } |
| 1524 | 885 |
| 1525 | 886 |
| 1526 void FloatingPointHelper::NumbersToSmis(MacroAssembler* masm, | |
| 1527 Register first, | |
| 1528 Register second, | |
| 1529 Register scratch1, | |
| 1530 Register scratch2, | |
| 1531 Register scratch3, | |
| 1532 Label* on_success, | |
| 1533 Label* on_not_smis, | |
| 1534 ConvertUndefined convert_undefined) { | |
| 1535 Register heap_number_map = scratch3; | |
| 1536 Register smi_result = scratch1; | |
| 1537 Label done, maybe_undefined_first, maybe_undefined_second, first_done; | |
| 1538 | |
| 1539 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
| 1540 | |
| 1541 Label first_smi; | |
| 1542 __ JumpIfSmi(first, &first_smi, Label::kNear); | |
| 1543 __ cmpq(FieldOperand(first, HeapObject::kMapOffset), heap_number_map); | |
| 1544 __ j(not_equal, | |
| 1545 (convert_undefined == CONVERT_UNDEFINED_TO_ZERO) | |
| 1546 ? &maybe_undefined_first | |
| 1547 : on_not_smis); | |
| 1548 // Convert HeapNumber to smi if possible. | |
| 1549 __ movsd(xmm0, FieldOperand(first, HeapNumber::kValueOffset)); | |
| 1550 __ movq(scratch2, xmm0); | |
| 1551 __ cvttsd2siq(smi_result, xmm0); | |
| 1552 // Check if conversion was successful by converting back and | |
| 1553 // comparing to the original double's bits. | |
| 1554 __ Cvtlsi2sd(xmm1, smi_result); | |
| 1555 __ movq(kScratchRegister, xmm1); | |
| 1556 __ cmpq(scratch2, kScratchRegister); | |
| 1557 __ j(not_equal, on_not_smis); | |
| 1558 __ Integer32ToSmi(first, smi_result); | |
| 1559 | |
| 1560 __ bind(&first_done); | |
| 1561 __ JumpIfSmi(second, (on_success != NULL) ? on_success : &done); | |
| 1562 __ bind(&first_smi); | |
| 1563 __ AssertNotSmi(second); | |
| 1564 __ cmpq(FieldOperand(second, HeapObject::kMapOffset), heap_number_map); | |
| 1565 __ j(not_equal, | |
| 1566 (convert_undefined == CONVERT_UNDEFINED_TO_ZERO) | |
| 1567 ? &maybe_undefined_second | |
| 1568 : on_not_smis); | |
| 1569 // Convert second to smi, if possible. | |
| 1570 __ movsd(xmm0, FieldOperand(second, HeapNumber::kValueOffset)); | |
| 1571 __ movq(scratch2, xmm0); | |
| 1572 __ cvttsd2siq(smi_result, xmm0); | |
| 1573 __ Cvtlsi2sd(xmm1, smi_result); | |
| 1574 __ movq(kScratchRegister, xmm1); | |
| 1575 __ cmpq(scratch2, kScratchRegister); | |
| 1576 __ j(not_equal, on_not_smis); | |
| 1577 __ Integer32ToSmi(second, smi_result); | |
| 1578 if (on_success != NULL) { | |
| 1579 __ jmp(on_success); | |
| 1580 } else { | |
| 1581 __ jmp(&done); | |
| 1582 } | |
| 1583 | |
| 1584 __ bind(&maybe_undefined_first); | |
| 1585 __ CompareRoot(first, Heap::kUndefinedValueRootIndex); | |
| 1586 __ j(not_equal, on_not_smis); | |
| 1587 __ xor_(first, first); | |
| 1588 __ jmp(&first_done); | |
| 1589 | |
| 1590 __ bind(&maybe_undefined_second); | |
| 1591 __ CompareRoot(second, Heap::kUndefinedValueRootIndex); | |
| 1592 __ j(not_equal, on_not_smis); | |
| 1593 __ xor_(second, second); | |
| 1594 if (on_success != NULL) { | |
| 1595 __ jmp(on_success); | |
| 1596 } | |
| 1597 // Else: fall through. | |
| 1598 | |
| 1599 __ bind(&done); | |
| 1600 } | |
| 1601 | |
| 1602 | |
| 1603 void MathPowStub::Generate(MacroAssembler* masm) { | 887 void MathPowStub::Generate(MacroAssembler* masm) { |
| 1604 const Register exponent = rdx; | 888 const Register exponent = rdx; |
| 1605 const Register base = rax; | 889 const Register base = rax; |
| 1606 const Register scratch = rcx; | 890 const Register scratch = rcx; |
| 1607 const XMMRegister double_result = xmm3; | 891 const XMMRegister double_result = xmm3; |
| 1608 const XMMRegister double_base = xmm2; | 892 const XMMRegister double_base = xmm2; |
| 1609 const XMMRegister double_exponent = xmm1; | 893 const XMMRegister double_exponent = xmm1; |
| 1610 const XMMRegister double_scratch = xmm4; | 894 const XMMRegister double_scratch = xmm4; |
| 1611 | 895 |
| 1612 Label call_runtime, done, exponent_not_smi, int_exponent; | 896 Label call_runtime, done, exponent_not_smi, int_exponent; |
| (...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1979 __ bind(&miss); | 1263 __ bind(&miss); |
| 1980 | 1264 |
| 1981 StubCompiler::TailCallBuiltin( | 1265 StubCompiler::TailCallBuiltin( |
| 1982 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); | 1266 masm, BaseLoadStoreStubCompiler::MissBuiltin(kind())); |
| 1983 } | 1267 } |
| 1984 | 1268 |
| 1985 | 1269 |
| 1986 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { | 1270 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { |
| 1987 // The key is in rdx and the parameter count is in rax. | 1271 // The key is in rdx and the parameter count is in rax. |
| 1988 | 1272 |
| 1989 // The displacement is used for skipping the frame pointer on the | |
| 1990 // stack. It is the offset of the last parameter (if any) relative | |
| 1991 // to the frame pointer. | |
| 1992 static const int kDisplacement = 1 * kPointerSize; | |
| 1993 | |
| 1994 // Check that the key is a smi. | 1273 // Check that the key is a smi. |
| 1995 Label slow; | 1274 Label slow; |
| 1996 __ JumpIfNotSmi(rdx, &slow); | 1275 __ JumpIfNotSmi(rdx, &slow); |
| 1997 | 1276 |
| 1998 // Check if the calling frame is an arguments adaptor frame. We look at the | 1277 // Check if the calling frame is an arguments adaptor frame. We look at the |
| 1999 // context offset, and if the frame is not a regular one, then we find a | 1278 // context offset, and if the frame is not a regular one, then we find a |
| 2000 // Smi instead of the context. We can't use SmiCompare here, because that | 1279 // Smi instead of the context. We can't use SmiCompare here, because that |
| 2001 // only works for comparing two smis. | 1280 // only works for comparing two smis. |
| 2002 Label adaptor; | 1281 Label adaptor; |
| 2003 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 1282 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2004 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), | 1283 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), |
| 2005 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 1284 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2006 __ j(equal, &adaptor); | 1285 __ j(equal, &adaptor); |
| 2007 | 1286 |
| 2008 // Check index against formal parameters count limit passed in | 1287 // Check index against formal parameters count limit passed in |
| 2009 // through register rax. Use unsigned comparison to get negative | 1288 // through register rax. Use unsigned comparison to get negative |
| 2010 // check for free. | 1289 // check for free. |
| 2011 __ cmpq(rdx, rax); | 1290 __ cmpq(rdx, rax); |
| 2012 __ j(above_equal, &slow); | 1291 __ j(above_equal, &slow); |
| 2013 | 1292 |
| 2014 // Read the argument from the stack and return it. | 1293 // Read the argument from the stack and return it. |
| 2015 SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); | 1294 __ SmiSub(rax, rax, rdx); |
| 2016 __ lea(rbx, Operand(rbp, index.reg, index.scale, 0)); | 1295 __ SmiToInteger32(rax, rax); |
| 2017 index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); | 1296 StackArgumentsAccessor args(rbp, rax, ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2018 __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); | 1297 __ movq(rax, args.GetArgumentOperand(0)); |
| 2019 __ Ret(); | 1298 __ Ret(); |
| 2020 | 1299 |
| 2021 // Arguments adaptor case: Check index against actual arguments | 1300 // Arguments adaptor case: Check index against actual arguments |
| 2022 // limit found in the arguments adaptor frame. Use unsigned | 1301 // limit found in the arguments adaptor frame. Use unsigned |
| 2023 // comparison to get negative check for free. | 1302 // comparison to get negative check for free. |
| 2024 __ bind(&adaptor); | 1303 __ bind(&adaptor); |
| 2025 __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 1304 __ movq(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2026 __ cmpq(rdx, rcx); | 1305 __ cmpq(rdx, rcx); |
| 2027 __ j(above_equal, &slow); | 1306 __ j(above_equal, &slow); |
| 2028 | 1307 |
| 2029 // Read the argument from the stack and return it. | 1308 // Read the argument from the stack and return it. |
| 2030 index = masm->SmiToIndex(rax, rcx, kPointerSizeLog2); | 1309 __ SmiSub(rcx, rcx, rdx); |
| 2031 __ lea(rbx, Operand(rbx, index.reg, index.scale, 0)); | 1310 __ SmiToInteger32(rcx, rcx); |
| 2032 index = masm->SmiToNegativeIndex(rdx, rdx, kPointerSizeLog2); | 1311 StackArgumentsAccessor adaptor_args(rbx, rcx, |
| 2033 __ movq(rax, Operand(rbx, index.reg, index.scale, kDisplacement)); | 1312 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 1313 __ movq(rax, adaptor_args.GetArgumentOperand(0)); |
| 2034 __ Ret(); | 1314 __ Ret(); |
| 2035 | 1315 |
| 2036 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 1316 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 2037 // by calling the runtime system. | 1317 // by calling the runtime system. |
| 2038 __ bind(&slow); | 1318 __ bind(&slow); |
| 2039 __ PopReturnAddressTo(rbx); | 1319 __ PopReturnAddressTo(rbx); |
| 2040 __ push(rdx); | 1320 __ push(rdx); |
| 2041 __ PushReturnAddressFrom(rbx); | 1321 __ PushReturnAddressFrom(rbx); |
| 2042 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); | 1322 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 2043 } | 1323 } |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2397 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 1677 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 2398 #else // V8_INTERPRETED_REGEXP | 1678 #else // V8_INTERPRETED_REGEXP |
| 2399 | 1679 |
| 2400 // Stack frame on entry. | 1680 // Stack frame on entry. |
| 2401 // rsp[0] : return address | 1681 // rsp[0] : return address |
| 2402 // rsp[8] : last_match_info (expected JSArray) | 1682 // rsp[8] : last_match_info (expected JSArray) |
| 2403 // rsp[16] : previous index | 1683 // rsp[16] : previous index |
| 2404 // rsp[24] : subject string | 1684 // rsp[24] : subject string |
| 2405 // rsp[32] : JSRegExp object | 1685 // rsp[32] : JSRegExp object |
| 2406 | 1686 |
| 2407 static const int kLastMatchInfoOffset = 1 * kPointerSize; | 1687 enum RegExpExecStubArgumentIndices { |
| 2408 static const int kPreviousIndexOffset = 2 * kPointerSize; | 1688 JS_REG_EXP_OBJECT_ARGUMENT_INDEX, |
| 2409 static const int kSubjectOffset = 3 * kPointerSize; | 1689 SUBJECT_STRING_ARGUMENT_INDEX, |
| 2410 static const int kJSRegExpOffset = 4 * kPointerSize; | 1690 PREVIOUS_INDEX_ARGUMENT_INDEX, |
| 1691 LAST_MATCH_INFO_ARGUMENT_INDEX, |
| 1692 REG_EXP_EXEC_ARGUMENT_COUNT |
| 1693 }; |
| 2411 | 1694 |
| 1695 StackArgumentsAccessor args(rsp, REG_EXP_EXEC_ARGUMENT_COUNT, |
| 1696 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2412 Label runtime; | 1697 Label runtime; |
| 2413 // Ensure that a RegExp stack is allocated. | 1698 // Ensure that a RegExp stack is allocated. |
| 2414 Isolate* isolate = masm->isolate(); | 1699 Isolate* isolate = masm->isolate(); |
| 2415 ExternalReference address_of_regexp_stack_memory_address = | 1700 ExternalReference address_of_regexp_stack_memory_address = |
| 2416 ExternalReference::address_of_regexp_stack_memory_address(isolate); | 1701 ExternalReference::address_of_regexp_stack_memory_address(isolate); |
| 2417 ExternalReference address_of_regexp_stack_memory_size = | 1702 ExternalReference address_of_regexp_stack_memory_size = |
| 2418 ExternalReference::address_of_regexp_stack_memory_size(isolate); | 1703 ExternalReference::address_of_regexp_stack_memory_size(isolate); |
| 2419 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); | 1704 __ Load(kScratchRegister, address_of_regexp_stack_memory_size); |
| 2420 __ testq(kScratchRegister, kScratchRegister); | 1705 __ testq(kScratchRegister, kScratchRegister); |
| 2421 __ j(zero, &runtime); | 1706 __ j(zero, &runtime); |
| 2422 | 1707 |
| 2423 // Check that the first argument is a JSRegExp object. | 1708 // Check that the first argument is a JSRegExp object. |
| 2424 __ movq(rax, Operand(rsp, kJSRegExpOffset)); | 1709 __ movq(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); |
| 2425 __ JumpIfSmi(rax, &runtime); | 1710 __ JumpIfSmi(rax, &runtime); |
| 2426 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); | 1711 __ CmpObjectType(rax, JS_REGEXP_TYPE, kScratchRegister); |
| 2427 __ j(not_equal, &runtime); | 1712 __ j(not_equal, &runtime); |
| 2428 | 1713 |
| 2429 // Check that the RegExp has been compiled (data contains a fixed array). | 1714 // Check that the RegExp has been compiled (data contains a fixed array). |
| 2430 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); | 1715 __ movq(rax, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 2431 if (FLAG_debug_code) { | 1716 if (FLAG_debug_code) { |
| 2432 Condition is_smi = masm->CheckSmi(rax); | 1717 Condition is_smi = masm->CheckSmi(rax); |
| 2433 __ Check(NegateCondition(is_smi), | 1718 __ Check(NegateCondition(is_smi), |
| 2434 kUnexpectedTypeForRegExpDataFixedArrayExpected); | 1719 kUnexpectedTypeForRegExpDataFixedArrayExpected); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2447 __ SmiToInteger32(rdx, | 1732 __ SmiToInteger32(rdx, |
| 2448 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); | 1733 FieldOperand(rax, JSRegExp::kIrregexpCaptureCountOffset)); |
| 2449 // Check (number_of_captures + 1) * 2 <= offsets vector size | 1734 // Check (number_of_captures + 1) * 2 <= offsets vector size |
| 2450 // Or number_of_captures <= offsets vector size / 2 - 1 | 1735 // Or number_of_captures <= offsets vector size / 2 - 1 |
| 2451 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); | 1736 STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2); |
| 2452 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); | 1737 __ cmpl(rdx, Immediate(Isolate::kJSRegexpStaticOffsetsVectorSize / 2 - 1)); |
| 2453 __ j(above, &runtime); | 1738 __ j(above, &runtime); |
| 2454 | 1739 |
| 2455 // Reset offset for possibly sliced string. | 1740 // Reset offset for possibly sliced string. |
| 2456 __ Set(r14, 0); | 1741 __ Set(r14, 0); |
| 2457 __ movq(rdi, Operand(rsp, kSubjectOffset)); | 1742 __ movq(rdi, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); |
| 2458 __ JumpIfSmi(rdi, &runtime); | 1743 __ JumpIfSmi(rdi, &runtime); |
| 2459 __ movq(r15, rdi); // Make a copy of the original subject string. | 1744 __ movq(r15, rdi); // Make a copy of the original subject string. |
| 2460 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); | 1745 __ movq(rbx, FieldOperand(rdi, HeapObject::kMapOffset)); |
| 2461 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 1746 __ movzxbl(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2462 // rax: RegExp data (FixedArray) | 1747 // rax: RegExp data (FixedArray) |
| 2463 // rdi: subject string | 1748 // rdi: subject string |
| 2464 // r15: subject string | 1749 // r15: subject string |
| 2465 // Handle subject string according to its encoding and representation: | 1750 // Handle subject string according to its encoding and representation: |
| 2466 // (1) Sequential two byte? If yes, go to (9). | 1751 // (1) Sequential two byte? If yes, go to (9). |
| 2467 // (2) Sequential one byte? If yes, go to (6). | 1752 // (2) Sequential one byte? If yes, go to (6). |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2549 | 1834 |
| 2550 // rdi: sequential subject string (or look-alike, external string) | 1835 // rdi: sequential subject string (or look-alike, external string) |
| 2551 // r15: original subject string | 1836 // r15: original subject string |
| 2552 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); | 1837 // rcx: encoding of subject string (1 if ASCII, 0 if two_byte); |
| 2553 // r11: code | 1838 // r11: code |
| 2554 // Load used arguments before starting to push arguments for call to native | 1839 // Load used arguments before starting to push arguments for call to native |
| 2555 // RegExp code to avoid handling changing stack height. | 1840 // RegExp code to avoid handling changing stack height. |
| 2556 // We have to use r15 instead of rdi to load the length because rdi might | 1841 // We have to use r15 instead of rdi to load the length because rdi might |
| 2557 // have been only made to look like a sequential string when it actually | 1842 // have been only made to look like a sequential string when it actually |
| 2558 // is an external string. | 1843 // is an external string. |
| 2559 __ movq(rbx, Operand(rsp, kPreviousIndexOffset)); | 1844 __ movq(rbx, args.GetArgumentOperand(PREVIOUS_INDEX_ARGUMENT_INDEX)); |
| 2560 __ JumpIfNotSmi(rbx, &runtime); | 1845 __ JumpIfNotSmi(rbx, &runtime); |
| 2561 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); | 1846 __ SmiCompare(rbx, FieldOperand(r15, String::kLengthOffset)); |
| 2562 __ j(above_equal, &runtime); | 1847 __ j(above_equal, &runtime); |
| 2563 __ SmiToInteger64(rbx, rbx); | 1848 __ SmiToInteger64(rbx, rbx); |
| 2564 | 1849 |
| 2565 // rdi: subject string | 1850 // rdi: subject string |
| 2566 // rbx: previous index | 1851 // rbx: previous index |
| 2567 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); | 1852 // rcx: encoding of subject string (1 if ASCII 0 if two_byte); |
| 2568 // r11: code | 1853 // r11: code |
| 2569 // All checks done. Now push arguments for native regexp code. | 1854 // All checks done. Now push arguments for native regexp code. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2669 __ j(equal, &success, Label::kNear); | 1954 __ j(equal, &success, Label::kNear); |
| 2670 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); | 1955 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::EXCEPTION)); |
| 2671 __ j(equal, &exception); | 1956 __ j(equal, &exception); |
| 2672 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); | 1957 __ cmpl(rax, Immediate(NativeRegExpMacroAssembler::FAILURE)); |
| 2673 // If none of the above, it can only be retry. | 1958 // If none of the above, it can only be retry. |
| 2674 // Handle that in the runtime system. | 1959 // Handle that in the runtime system. |
| 2675 __ j(not_equal, &runtime); | 1960 __ j(not_equal, &runtime); |
| 2676 | 1961 |
| 2677 // For failure return null. | 1962 // For failure return null. |
| 2678 __ LoadRoot(rax, Heap::kNullValueRootIndex); | 1963 __ LoadRoot(rax, Heap::kNullValueRootIndex); |
| 2679 __ ret(4 * kPointerSize); | 1964 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); |
| 2680 | 1965 |
| 2681 // Load RegExp data. | 1966 // Load RegExp data. |
| 2682 __ bind(&success); | 1967 __ bind(&success); |
| 2683 __ movq(rax, Operand(rsp, kJSRegExpOffset)); | 1968 __ movq(rax, args.GetArgumentOperand(JS_REG_EXP_OBJECT_ARGUMENT_INDEX)); |
| 2684 __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); | 1969 __ movq(rcx, FieldOperand(rax, JSRegExp::kDataOffset)); |
| 2685 __ SmiToInteger32(rax, | 1970 __ SmiToInteger32(rax, |
| 2686 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); | 1971 FieldOperand(rcx, JSRegExp::kIrregexpCaptureCountOffset)); |
| 2687 // Calculate number of capture registers (number_of_captures + 1) * 2. | 1972 // Calculate number of capture registers (number_of_captures + 1) * 2. |
| 2688 __ leal(rdx, Operand(rax, rax, times_1, 2)); | 1973 __ leal(rdx, Operand(rax, rax, times_1, 2)); |
| 2689 | 1974 |
| 2690 // rdx: Number of capture registers | 1975 // rdx: Number of capture registers |
| 2691 // Check that the fourth object is a JSArray object. | 1976 // Check that the fourth object is a JSArray object. |
| 2692 __ movq(r15, Operand(rsp, kLastMatchInfoOffset)); | 1977 __ movq(r15, args.GetArgumentOperand(LAST_MATCH_INFO_ARGUMENT_INDEX)); |
| 2693 __ JumpIfSmi(r15, &runtime); | 1978 __ JumpIfSmi(r15, &runtime); |
| 2694 __ CmpObjectType(r15, JS_ARRAY_TYPE, kScratchRegister); | 1979 __ CmpObjectType(r15, JS_ARRAY_TYPE, kScratchRegister); |
| 2695 __ j(not_equal, &runtime); | 1980 __ j(not_equal, &runtime); |
| 2696 // Check that the JSArray is in fast case. | 1981 // Check that the JSArray is in fast case. |
| 2697 __ movq(rbx, FieldOperand(r15, JSArray::kElementsOffset)); | 1982 __ movq(rbx, FieldOperand(r15, JSArray::kElementsOffset)); |
| 2698 __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset)); | 1983 __ movq(rax, FieldOperand(rbx, HeapObject::kMapOffset)); |
| 2699 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); | 1984 __ CompareRoot(rax, Heap::kFixedArrayMapRootIndex); |
| 2700 __ j(not_equal, &runtime); | 1985 __ j(not_equal, &runtime); |
| 2701 // Check that the last match info has space for the capture registers and the | 1986 // Check that the last match info has space for the capture registers and the |
| 2702 // additional information. Ensure no overflow in add. | 1987 // additional information. Ensure no overflow in add. |
| 2703 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); | 1988 STATIC_ASSERT(FixedArray::kMaxLength < kMaxInt - FixedArray::kLengthOffset); |
| 2704 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); | 1989 __ SmiToInteger32(rax, FieldOperand(rbx, FixedArray::kLengthOffset)); |
| 2705 __ subl(rax, Immediate(RegExpImpl::kLastMatchOverhead)); | 1990 __ subl(rax, Immediate(RegExpImpl::kLastMatchOverhead)); |
| 2706 __ cmpl(rdx, rax); | 1991 __ cmpl(rdx, rax); |
| 2707 __ j(greater, &runtime); | 1992 __ j(greater, &runtime); |
| 2708 | 1993 |
| 2709 // rbx: last_match_info backing store (FixedArray) | 1994 // rbx: last_match_info backing store (FixedArray) |
| 2710 // rdx: number of capture registers | 1995 // rdx: number of capture registers |
| 2711 // Store the capture count. | 1996 // Store the capture count. |
| 2712 __ Integer32ToSmi(kScratchRegister, rdx); | 1997 __ Integer32ToSmi(kScratchRegister, rdx); |
| 2713 __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), | 1998 __ movq(FieldOperand(rbx, RegExpImpl::kLastCaptureCountOffset), |
| 2714 kScratchRegister); | 1999 kScratchRegister); |
| 2715 // Store last subject and last input. | 2000 // Store last subject and last input. |
| 2716 __ movq(rax, Operand(rsp, kSubjectOffset)); | 2001 __ movq(rax, args.GetArgumentOperand(SUBJECT_STRING_ARGUMENT_INDEX)); |
| 2717 __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); | 2002 __ movq(FieldOperand(rbx, RegExpImpl::kLastSubjectOffset), rax); |
| 2718 __ movq(rcx, rax); | 2003 __ movq(rcx, rax); |
| 2719 __ RecordWriteField(rbx, | 2004 __ RecordWriteField(rbx, |
| 2720 RegExpImpl::kLastSubjectOffset, | 2005 RegExpImpl::kLastSubjectOffset, |
| 2721 rax, | 2006 rax, |
| 2722 rdi, | 2007 rdi, |
| 2723 kDontSaveFPRegs); | 2008 kDontSaveFPRegs); |
| 2724 __ movq(rax, rcx); | 2009 __ movq(rax, rcx); |
| 2725 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); | 2010 __ movq(FieldOperand(rbx, RegExpImpl::kLastInputOffset), rax); |
| 2726 __ RecordWriteField(rbx, | 2011 __ RecordWriteField(rbx, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2749 __ movq(FieldOperand(rbx, | 2034 __ movq(FieldOperand(rbx, |
| 2750 rdx, | 2035 rdx, |
| 2751 times_pointer_size, | 2036 times_pointer_size, |
| 2752 RegExpImpl::kFirstCaptureOffset), | 2037 RegExpImpl::kFirstCaptureOffset), |
| 2753 rdi); | 2038 rdi); |
| 2754 __ jmp(&next_capture); | 2039 __ jmp(&next_capture); |
| 2755 __ bind(&done); | 2040 __ bind(&done); |
| 2756 | 2041 |
| 2757 // Return last match info. | 2042 // Return last match info. |
| 2758 __ movq(rax, r15); | 2043 __ movq(rax, r15); |
| 2759 __ ret(4 * kPointerSize); | 2044 __ ret(REG_EXP_EXEC_ARGUMENT_COUNT * kPointerSize); |
| 2760 | 2045 |
| 2761 __ bind(&exception); | 2046 __ bind(&exception); |
| 2762 // Result must now be exception. If there is no pending exception already a | 2047 // Result must now be exception. If there is no pending exception already a |
| 2763 // stack overflow (on the backtrack stack) was detected in RegExp code but | 2048 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| 2764 // haven't created the exception yet. Handle that in the runtime system. | 2049 // haven't created the exception yet. Handle that in the runtime system. |
| 2765 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 2050 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
| 2766 ExternalReference pending_exception_address( | 2051 ExternalReference pending_exception_address( |
| 2767 Isolate::kPendingExceptionAddress, isolate); | 2052 Isolate::kPendingExceptionAddress, isolate); |
| 2768 Operand pending_exception_operand = | 2053 Operand pending_exception_operand = |
| 2769 masm->ExternalOperand(pending_exception_address, rbx); | 2054 masm->ExternalOperand(pending_exception_address, rbx); |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3459 | 2744 |
| 3460 | 2745 |
| 3461 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { | 2746 void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) { |
| 3462 CEntryStub::GenerateAheadOfTime(isolate); | 2747 CEntryStub::GenerateAheadOfTime(isolate); |
| 3463 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 2748 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 3464 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 2749 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 3465 // It is important that the store buffer overflow stubs are generated first. | 2750 // It is important that the store buffer overflow stubs are generated first. |
| 3466 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); | 2751 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 3467 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 2752 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 3468 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 2753 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
| 2754 BinaryOpStub::GenerateAheadOfTime(isolate); |
| 3469 } | 2755 } |
| 3470 | 2756 |
| 3471 | 2757 |
| 3472 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 2758 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 3473 } | 2759 } |
| 3474 | 2760 |
| 3475 | 2761 |
| 3476 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { | 2762 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) { |
| 3477 CEntryStub stub(1, kDontSaveFPRegs); | 2763 CEntryStub stub(1, kDontSaveFPRegs); |
| 3478 stub.GetCode(isolate)->set_is_pregenerated(true); | 2764 stub.GetCode(isolate)->set_is_pregenerated(true); |
| (...skipping 1349 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4828 | 4114 |
| 4829 void SubStringStub::Generate(MacroAssembler* masm) { | 4115 void SubStringStub::Generate(MacroAssembler* masm) { |
| 4830 Label runtime; | 4116 Label runtime; |
| 4831 | 4117 |
| 4832 // Stack frame on entry. | 4118 // Stack frame on entry. |
| 4833 // rsp[0] : return address | 4119 // rsp[0] : return address |
| 4834 // rsp[8] : to | 4120 // rsp[8] : to |
| 4835 // rsp[16] : from | 4121 // rsp[16] : from |
| 4836 // rsp[24] : string | 4122 // rsp[24] : string |
| 4837 | 4123 |
| 4838 const int kToOffset = 1 * kPointerSize; | 4124 enum SubStringStubArgumentIndices { |
| 4839 const int kFromOffset = kToOffset + kPointerSize; | 4125 STRING_ARGUMENT_INDEX, |
| 4840 const int kStringOffset = kFromOffset + kPointerSize; | 4126 FROM_ARGUMENT_INDEX, |
| 4841 const int kArgumentsSize = (kStringOffset + kPointerSize) - kToOffset; | 4127 TO_ARGUMENT_INDEX, |
| 4128 SUB_STRING_ARGUMENT_COUNT |
| 4129 }; |
| 4130 |
| 4131 StackArgumentsAccessor args(rsp, SUB_STRING_ARGUMENT_COUNT, |
| 4132 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 4842 | 4133 |
| 4843 // Make sure first argument is a string. | 4134 // Make sure first argument is a string. |
| 4844 __ movq(rax, Operand(rsp, kStringOffset)); | 4135 __ movq(rax, args.GetArgumentOperand(STRING_ARGUMENT_INDEX)); |
| 4845 STATIC_ASSERT(kSmiTag == 0); | 4136 STATIC_ASSERT(kSmiTag == 0); |
| 4846 __ testl(rax, Immediate(kSmiTagMask)); | 4137 __ testl(rax, Immediate(kSmiTagMask)); |
| 4847 __ j(zero, &runtime); | 4138 __ j(zero, &runtime); |
| 4848 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); | 4139 Condition is_string = masm->IsObjectStringType(rax, rbx, rbx); |
| 4849 __ j(NegateCondition(is_string), &runtime); | 4140 __ j(NegateCondition(is_string), &runtime); |
| 4850 | 4141 |
| 4851 // rax: string | 4142 // rax: string |
| 4852 // rbx: instance type | 4143 // rbx: instance type |
| 4853 // Calculate length of sub string using the smi values. | 4144 // Calculate length of sub string using the smi values. |
| 4854 __ movq(rcx, Operand(rsp, kToOffset)); | 4145 __ movq(rcx, args.GetArgumentOperand(TO_ARGUMENT_INDEX)); |
| 4855 __ movq(rdx, Operand(rsp, kFromOffset)); | 4146 __ movq(rdx, args.GetArgumentOperand(FROM_ARGUMENT_INDEX)); |
| 4856 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); | 4147 __ JumpUnlessBothNonNegativeSmi(rcx, rdx, &runtime); |
| 4857 | 4148 |
| 4858 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. | 4149 __ SmiSub(rcx, rcx, rdx); // Overflow doesn't happen. |
| 4859 __ cmpq(rcx, FieldOperand(rax, String::kLengthOffset)); | 4150 __ cmpq(rcx, FieldOperand(rax, String::kLengthOffset)); |
| 4860 Label not_original_string; | 4151 Label not_original_string; |
| 4861 // Shorter than original string's length: an actual substring. | 4152 // Shorter than original string's length: an actual substring. |
| 4862 __ j(below, ¬_original_string, Label::kNear); | 4153 __ j(below, ¬_original_string, Label::kNear); |
| 4863 // Longer than original string's length or negative: unsafe arguments. | 4154 // Longer than original string's length or negative: unsafe arguments. |
| 4864 __ j(above, &runtime); | 4155 __ j(above, &runtime); |
| 4865 // Return original string. | 4156 // Return original string. |
| 4866 Counters* counters = masm->isolate()->counters(); | 4157 Counters* counters = masm->isolate()->counters(); |
| 4867 __ IncrementCounter(counters->sub_string_native(), 1); | 4158 __ IncrementCounter(counters->sub_string_native(), 1); |
| 4868 __ ret(kArgumentsSize); | 4159 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 4869 __ bind(¬_original_string); | 4160 __ bind(¬_original_string); |
| 4870 | 4161 |
| 4871 Label single_char; | 4162 Label single_char; |
| 4872 __ SmiCompare(rcx, Smi::FromInt(1)); | 4163 __ SmiCompare(rcx, Smi::FromInt(1)); |
| 4873 __ j(equal, &single_char); | 4164 __ j(equal, &single_char); |
| 4874 | 4165 |
| 4875 __ SmiToInteger32(rcx, rcx); | 4166 __ SmiToInteger32(rcx, rcx); |
| 4876 | 4167 |
| 4877 // rax: string | 4168 // rax: string |
| 4878 // rbx: instance type | 4169 // rbx: instance type |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4941 __ bind(&two_byte_slice); | 4232 __ bind(&two_byte_slice); |
| 4942 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); | 4233 __ AllocateTwoByteSlicedString(rax, rbx, r14, &runtime); |
| 4943 __ bind(&set_slice_header); | 4234 __ bind(&set_slice_header); |
| 4944 __ Integer32ToSmi(rcx, rcx); | 4235 __ Integer32ToSmi(rcx, rcx); |
| 4945 __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); | 4236 __ movq(FieldOperand(rax, SlicedString::kLengthOffset), rcx); |
| 4946 __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), | 4237 __ movq(FieldOperand(rax, SlicedString::kHashFieldOffset), |
| 4947 Immediate(String::kEmptyHashField)); | 4238 Immediate(String::kEmptyHashField)); |
| 4948 __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); | 4239 __ movq(FieldOperand(rax, SlicedString::kParentOffset), rdi); |
| 4949 __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); | 4240 __ movq(FieldOperand(rax, SlicedString::kOffsetOffset), rdx); |
| 4950 __ IncrementCounter(counters->sub_string_native(), 1); | 4241 __ IncrementCounter(counters->sub_string_native(), 1); |
| 4951 __ ret(kArgumentsSize); | 4242 __ ret(3 * kPointerSize); |
| 4952 | 4243 |
| 4953 __ bind(©_routine); | 4244 __ bind(©_routine); |
| 4954 } | 4245 } |
| 4955 | 4246 |
| 4956 // rdi: underlying subject string | 4247 // rdi: underlying subject string |
| 4957 // rbx: instance type of underlying subject string | 4248 // rbx: instance type of underlying subject string |
| 4958 // rdx: adjusted start index (smi) | 4249 // rdx: adjusted start index (smi) |
| 4959 // rcx: length | 4250 // rcx: length |
| 4960 // The subject string can only be external or sequential string of either | 4251 // The subject string can only be external or sequential string of either |
| 4961 // encoding at this point. | 4252 // encoding at this point. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4995 __ lea(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); | 4286 __ lea(rdi, FieldOperand(rax, SeqOneByteString::kHeaderSize)); |
| 4996 | 4287 |
| 4997 // rax: result string | 4288 // rax: result string |
| 4998 // rcx: result length | 4289 // rcx: result length |
| 4999 // rdi: first character of result | 4290 // rdi: first character of result |
| 5000 // rsi: character of sub string start | 4291 // rsi: character of sub string start |
| 5001 // r14: original value of rsi | 4292 // r14: original value of rsi |
| 5002 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); | 4293 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, true); |
| 5003 __ movq(rsi, r14); // Restore rsi. | 4294 __ movq(rsi, r14); // Restore rsi. |
| 5004 __ IncrementCounter(counters->sub_string_native(), 1); | 4295 __ IncrementCounter(counters->sub_string_native(), 1); |
| 5005 __ ret(kArgumentsSize); | 4296 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 5006 | 4297 |
| 5007 __ bind(&two_byte_sequential); | 4298 __ bind(&two_byte_sequential); |
| 5008 // Allocate the result. | 4299 // Allocate the result. |
| 5009 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); | 4300 __ AllocateTwoByteString(rax, rcx, r11, r14, r15, &runtime); |
| 5010 | 4301 |
| 5011 // rax: result string | 4302 // rax: result string |
| 5012 // rcx: result string length | 4303 // rcx: result string length |
| 5013 __ movq(r14, rsi); // esi used by following code. | 4304 __ movq(r14, rsi); // esi used by following code. |
| 5014 { // Locate character of sub string start. | 4305 { // Locate character of sub string start. |
| 5015 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); | 4306 SmiIndex smi_as_index = masm->SmiToIndex(rdx, rdx, times_2); |
| 5016 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, | 4307 __ lea(rsi, Operand(rdi, smi_as_index.reg, smi_as_index.scale, |
| 5017 SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 4308 SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 5018 } | 4309 } |
| 5019 // Locate first character of result. | 4310 // Locate first character of result. |
| 5020 __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); | 4311 __ lea(rdi, FieldOperand(rax, SeqTwoByteString::kHeaderSize)); |
| 5021 | 4312 |
| 5022 // rax: result string | 4313 // rax: result string |
| 5023 // rcx: result length | 4314 // rcx: result length |
| 5024 // rdi: first character of result | 4315 // rdi: first character of result |
| 5025 // rsi: character of sub string start | 4316 // rsi: character of sub string start |
| 5026 // r14: original value of rsi | 4317 // r14: original value of rsi |
| 5027 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); | 4318 StringHelper::GenerateCopyCharactersREP(masm, rdi, rsi, rcx, false); |
| 5028 __ movq(rsi, r14); // Restore esi. | 4319 __ movq(rsi, r14); // Restore esi. |
| 5029 __ IncrementCounter(counters->sub_string_native(), 1); | 4320 __ IncrementCounter(counters->sub_string_native(), 1); |
| 5030 __ ret(kArgumentsSize); | 4321 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 5031 | 4322 |
| 5032 // Just jump to runtime to create the sub string. | 4323 // Just jump to runtime to create the sub string. |
| 5033 __ bind(&runtime); | 4324 __ bind(&runtime); |
| 5034 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 4325 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 5035 | 4326 |
| 5036 __ bind(&single_char); | 4327 __ bind(&single_char); |
| 5037 // rax: string | 4328 // rax: string |
| 5038 // rbx: instance type | 4329 // rbx: instance type |
| 5039 // rcx: sub string length (smi) | 4330 // rcx: sub string length (smi) |
| 5040 // rdx: from index (smi) | 4331 // rdx: from index (smi) |
| 5041 StringCharAtGenerator generator( | 4332 StringCharAtGenerator generator( |
| 5042 rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); | 4333 rax, rdx, rcx, rax, &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER); |
| 5043 generator.GenerateFast(masm); | 4334 generator.GenerateFast(masm); |
| 5044 __ ret(kArgumentsSize); | 4335 __ ret(SUB_STRING_ARGUMENT_COUNT * kPointerSize); |
| 5045 generator.SkipSlow(masm, &runtime); | 4336 generator.SkipSlow(masm, &runtime); |
| 5046 } | 4337 } |
| 5047 | 4338 |
| 5048 | 4339 |
| 5049 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, | 4340 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
| 5050 Register left, | 4341 Register left, |
| 5051 Register right, | 4342 Register right, |
| 5052 Register scratch1, | 4343 Register scratch1, |
| 5053 Register scratch2) { | 4344 Register scratch2) { |
| 5054 Register length = scratch1; | 4345 Register length = scratch1; |
| (...skipping 1485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6540 __ bind(&fast_elements_case); | 5831 __ bind(&fast_elements_case); |
| 6541 GenerateCase(masm, FAST_ELEMENTS); | 5832 GenerateCase(masm, FAST_ELEMENTS); |
| 6542 } | 5833 } |
| 6543 | 5834 |
| 6544 | 5835 |
| 6545 #undef __ | 5836 #undef __ |
| 6546 | 5837 |
| 6547 } } // namespace v8::internal | 5838 } } // namespace v8::internal |
| 6548 | 5839 |
| 6549 #endif // V8_TARGET_ARCH_X64 | 5840 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |