Revision f230a1cf deps/v8/src/ia32/code-stubs-ia32.cc
deps/v8/src/ia32/code-stubs-ia32.cc | ||
---|---|---|
64 | 64 |
} |
65 | 65 |
|
66 | 66 |
|
67 |
void NumberToStringStub::InitializeInterfaceDescriptor( |
|
68 |
Isolate* isolate, |
|
69 |
CodeStubInterfaceDescriptor* descriptor) { |
|
70 |
static Register registers[] = { eax }; |
|
71 |
descriptor->register_param_count_ = 1; |
|
72 |
descriptor->register_params_ = registers; |
|
73 |
descriptor->deoptimization_handler_ = |
|
74 |
Runtime::FunctionForId(Runtime::kNumberToString)->entry; |
|
75 |
} |
|
76 |
|
|
77 |
|
|
67 | 78 |
void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( |
68 | 79 |
Isolate* isolate, |
69 | 80 |
CodeStubInterfaceDescriptor* descriptor) { |
... | ... | |
82 | 93 |
descriptor->register_param_count_ = 4; |
83 | 94 |
descriptor->register_params_ = registers; |
84 | 95 |
descriptor->deoptimization_handler_ = |
85 |
Runtime::FunctionForId(Runtime::kCreateObjectLiteralShallow)->entry;
|
|
96 |
Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry; |
|
86 | 97 |
} |
87 | 98 |
|
88 | 99 |
|
... | ... | |
162 | 173 |
|
163 | 174 |
if (constant_stack_parameter_count != 0) { |
164 | 175 |
// stack param count needs (constructor pointer, and single argument) |
165 |
descriptor->stack_parameter_count_ = &eax;
|
|
176 |
descriptor->stack_parameter_count_ = eax; |
|
166 | 177 |
} |
167 | 178 |
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; |
168 | 179 |
descriptor->register_params_ = registers; |
... | ... | |
184 | 195 |
|
185 | 196 |
if (constant_stack_parameter_count != 0) { |
186 | 197 |
// stack param count needs (constructor pointer, and single argument) |
187 |
descriptor->stack_parameter_count_ = &eax;
|
|
198 |
descriptor->stack_parameter_count_ = eax; |
|
188 | 199 |
} |
189 | 200 |
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count; |
190 | 201 |
descriptor->register_params_ = registers; |
... | ... | |
283 | 294 |
} |
284 | 295 |
|
285 | 296 |
|
297 |
void BinaryOpStub::InitializeInterfaceDescriptor( |
|
298 |
Isolate* isolate, |
|
299 |
CodeStubInterfaceDescriptor* descriptor) { |
|
300 |
static Register registers[] = { edx, eax }; |
|
301 |
descriptor->register_param_count_ = 2; |
|
302 |
descriptor->register_params_ = registers; |
|
303 |
descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss); |
|
304 |
descriptor->SetMissHandler( |
|
305 |
ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate)); |
|
306 |
} |
|
307 |
|
|
308 |
|
|
286 | 309 |
#define __ ACCESS_MASM(masm) |
287 | 310 |
|
288 | 311 |
|
... | ... | |
432 | 455 |
__ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
433 | 456 |
for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
434 | 457 |
XMMRegister reg = XMMRegister::from_code(i); |
435 |
__ movdbl(Operand(esp, i * kDoubleSize), reg);
|
|
458 |
__ movsd(Operand(esp, i * kDoubleSize), reg);
|
|
436 | 459 |
} |
437 | 460 |
} |
438 | 461 |
const int argument_count = 1; |
... | ... | |
448 | 471 |
CpuFeatureScope scope(masm, SSE2); |
449 | 472 |
for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
450 | 473 |
XMMRegister reg = XMMRegister::from_code(i); |
451 |
__ movdbl(reg, Operand(esp, i * kDoubleSize));
|
|
474 |
__ movsd(reg, Operand(esp, i * kDoubleSize));
|
|
452 | 475 |
} |
453 | 476 |
__ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
454 | 477 |
} |
... | ... | |
470 | 493 |
// on FPU stack. |
471 | 494 |
static void LoadFloatOperand(MacroAssembler* masm, Register number); |
472 | 495 |
|
473 |
// Code pattern for loading floating point values. Input values must |
|
474 |
// be either smi or heap number objects (fp values). Requirements: |
|
475 |
// operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. |
|
476 |
// Returns operands as floating point numbers on FPU stack. |
|
477 |
static void LoadFloatOperands(MacroAssembler* masm, |
|
478 |
Register scratch, |
|
479 |
ArgLocation arg_location = ARGS_ON_STACK); |
|
480 |
|
|
481 |
// Similar to LoadFloatOperand but assumes that both operands are smis. |
|
482 |
// Expects operands in edx, eax. |
|
483 |
static void LoadFloatSmis(MacroAssembler* masm, Register scratch); |
|
484 |
|
|
485 | 496 |
// Test if operands are smi or number objects (fp). Requirements: |
486 | 497 |
// operand_1 in eax, operand_2 in edx; falls through on float |
487 | 498 |
// operands, jumps to the non_float label otherwise. |
... | ... | |
489 | 500 |
Label* non_float, |
490 | 501 |
Register scratch); |
491 | 502 |
|
492 |
// Takes the operands in edx and eax and loads them as integers in eax |
|
493 |
// and ecx. |
|
494 |
static void LoadUnknownsAsIntegers(MacroAssembler* masm, |
|
495 |
bool use_sse3, |
|
496 |
BinaryOpIC::TypeInfo left_type, |
|
497 |
BinaryOpIC::TypeInfo right_type, |
|
498 |
Label* operand_conversion_failure); |
|
499 |
|
|
500 | 503 |
// Test if operands are numbers (smi or HeapNumber objects), and load |
501 | 504 |
// them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
502 | 505 |
// either operand is not a number. Operands are in edx and eax. |
503 | 506 |
// Leaves operands unchanged. |
504 | 507 |
static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); |
505 |
|
|
506 |
// Similar to LoadSSE2Operands but assumes that both operands are smis. |
|
507 |
// Expects operands in edx, eax. |
|
508 |
static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); |
|
509 |
|
|
510 |
// Checks that |operand| has an int32 value. If |int32_result| is different |
|
511 |
// from |scratch|, it will contain that int32 value. |
|
512 |
static void CheckSSE2OperandIsInt32(MacroAssembler* masm, |
|
513 |
Label* non_int32, |
|
514 |
XMMRegister operand, |
|
515 |
Register int32_result, |
|
516 |
Register scratch, |
|
517 |
XMMRegister xmm_scratch); |
|
518 | 508 |
}; |
519 | 509 |
|
520 | 510 |
|
... | ... | |
658 | 648 |
} |
659 | 649 |
|
660 | 650 |
|
661 |
void BinaryOpStub::Initialize() { |
|
662 |
platform_specific_bit_ = CpuFeatures::IsSupported(SSE3); |
|
663 |
} |
|
664 |
|
|
665 |
|
|
666 |
void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
|
667 |
__ pop(ecx); // Save return address. |
|
668 |
__ push(edx); |
|
669 |
__ push(eax); |
|
670 |
// Left and right arguments are now on top. |
|
671 |
__ push(Immediate(Smi::FromInt(MinorKey()))); |
|
672 |
|
|
673 |
__ push(ecx); // Push return address. |
|
674 |
|
|
675 |
// Patch the caller to an appropriate specialized stub and return the |
|
676 |
// operation result to the caller of the stub. |
|
677 |
__ TailCallExternalReference( |
|
678 |
ExternalReference(IC_Utility(IC::kBinaryOp_Patch), |
|
679 |
masm->isolate()), |
|
680 |
3, |
|
681 |
1); |
|
682 |
} |
|
683 |
|
|
684 |
|
|
685 |
// Prepare for a type transition runtime call when the args are already on |
|
686 |
// the stack, under the return address. |
|
687 |
void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { |
|
688 |
__ pop(ecx); // Save return address. |
|
689 |
// Left and right arguments are already on top of the stack. |
|
690 |
__ push(Immediate(Smi::FromInt(MinorKey()))); |
|
691 |
|
|
692 |
__ push(ecx); // Push return address. |
|
693 |
|
|
694 |
// Patch the caller to an appropriate specialized stub and return the |
|
695 |
// operation result to the caller of the stub. |
|
696 |
__ TailCallExternalReference( |
|
697 |
ExternalReference(IC_Utility(IC::kBinaryOp_Patch), |
|
698 |
masm->isolate()), |
|
699 |
3, |
|
700 |
1); |
|
701 |
} |
|
702 |
|
|
703 |
|
|
704 |
static void BinaryOpStub_GenerateRegisterArgsPop(MacroAssembler* masm) { |
|
705 |
__ pop(ecx); |
|
706 |
__ pop(eax); |
|
707 |
__ pop(edx); |
|
708 |
__ push(ecx); |
|
709 |
} |
|
710 |
|
|
711 |
|
|
712 |
static void BinaryOpStub_GenerateSmiCode( |
|
713 |
MacroAssembler* masm, |
|
714 |
Label* slow, |
|
715 |
BinaryOpStub::SmiCodeGenerateHeapNumberResults allow_heapnumber_results, |
|
716 |
Token::Value op) { |
|
717 |
// 1. Move arguments into edx, eax except for DIV and MOD, which need the |
|
718 |
// dividend in eax and edx free for the division. Use eax, ebx for those. |
|
719 |
Comment load_comment(masm, "-- Load arguments"); |
|
720 |
Register left = edx; |
|
721 |
Register right = eax; |
|
722 |
if (op == Token::DIV || op == Token::MOD) { |
|
723 |
left = eax; |
|
724 |
right = ebx; |
|
725 |
__ mov(ebx, eax); |
|
726 |
__ mov(eax, edx); |
|
727 |
} |
|
728 |
|
|
729 |
|
|
730 |
// 2. Prepare the smi check of both operands by oring them together. |
|
731 |
Comment smi_check_comment(masm, "-- Smi check arguments"); |
|
732 |
Label not_smis; |
|
733 |
Register combined = ecx; |
|
734 |
ASSERT(!left.is(combined) && !right.is(combined)); |
|
735 |
switch (op) { |
|
736 |
case Token::BIT_OR: |
|
737 |
// Perform the operation into eax and smi check the result. Preserve |
|
738 |
// eax in case the result is not a smi. |
|
739 |
ASSERT(!left.is(ecx) && !right.is(ecx)); |
|
740 |
__ mov(ecx, right); |
|
741 |
__ or_(right, left); // Bitwise or is commutative. |
|
742 |
combined = right; |
|
743 |
break; |
|
744 |
|
|
745 |
case Token::BIT_XOR: |
|
746 |
case Token::BIT_AND: |
|
747 |
case Token::ADD: |
|
748 |
case Token::SUB: |
|
749 |
case Token::MUL: |
|
750 |
case Token::DIV: |
|
751 |
case Token::MOD: |
|
752 |
__ mov(combined, right); |
|
753 |
__ or_(combined, left); |
|
754 |
break; |
|
755 |
|
|
756 |
case Token::SHL: |
|
757 |
case Token::SAR: |
|
758 |
case Token::SHR: |
|
759 |
// Move the right operand into ecx for the shift operation, use eax |
|
760 |
// for the smi check register. |
|
761 |
ASSERT(!left.is(ecx) && !right.is(ecx)); |
|
762 |
__ mov(ecx, right); |
|
763 |
__ or_(right, left); |
|
764 |
combined = right; |
|
765 |
break; |
|
766 |
|
|
767 |
default: |
|
768 |
break; |
|
769 |
} |
|
770 |
|
|
771 |
// 3. Perform the smi check of the operands. |
|
772 |
STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. |
|
773 |
__ JumpIfNotSmi(combined, ¬_smis); |
|
774 |
|
|
775 |
// 4. Operands are both smis, perform the operation leaving the result in |
|
776 |
// eax and check the result if necessary. |
|
777 |
Comment perform_smi(masm, "-- Perform smi operation"); |
|
778 |
Label use_fp_on_smis; |
|
779 |
switch (op) { |
|
780 |
case Token::BIT_OR: |
|
781 |
// Nothing to do. |
|
782 |
break; |
|
783 |
|
|
784 |
case Token::BIT_XOR: |
|
785 |
ASSERT(right.is(eax)); |
|
786 |
__ xor_(right, left); // Bitwise xor is commutative. |
|
787 |
break; |
|
788 |
|
|
789 |
case Token::BIT_AND: |
|
790 |
ASSERT(right.is(eax)); |
|
791 |
__ and_(right, left); // Bitwise and is commutative. |
|
792 |
break; |
|
793 |
|
|
794 |
case Token::SHL: |
|
795 |
// Remove tags from operands (but keep sign). |
|
796 |
__ SmiUntag(left); |
|
797 |
__ SmiUntag(ecx); |
|
798 |
// Perform the operation. |
|
799 |
__ shl_cl(left); |
|
800 |
// Check that the *signed* result fits in a smi. |
|
801 |
__ cmp(left, 0xc0000000); |
|
802 |
__ j(sign, &use_fp_on_smis); |
|
803 |
// Tag the result and store it in register eax. |
|
804 |
__ SmiTag(left); |
|
805 |
__ mov(eax, left); |
|
806 |
break; |
|
807 |
|
|
808 |
case Token::SAR: |
|
809 |
// Remove tags from operands (but keep sign). |
|
810 |
__ SmiUntag(left); |
|
811 |
__ SmiUntag(ecx); |
|
812 |
// Perform the operation. |
|
813 |
__ sar_cl(left); |
|
814 |
// Tag the result and store it in register eax. |
|
815 |
__ SmiTag(left); |
|
816 |
__ mov(eax, left); |
|
817 |
break; |
|
818 |
|
|
819 |
case Token::SHR: |
|
820 |
// Remove tags from operands (but keep sign). |
|
821 |
__ SmiUntag(left); |
|
822 |
__ SmiUntag(ecx); |
|
823 |
// Perform the operation. |
|
824 |
__ shr_cl(left); |
|
825 |
// Check that the *unsigned* result fits in a smi. |
|
826 |
// Neither of the two high-order bits can be set: |
|
827 |
// - 0x80000000: high bit would be lost when smi tagging. |
|
828 |
// - 0x40000000: this number would convert to negative when |
|
829 |
// Smi tagging these two cases can only happen with shifts |
|
830 |
// by 0 or 1 when handed a valid smi. |
|
831 |
__ test(left, Immediate(0xc0000000)); |
|
832 |
__ j(not_zero, &use_fp_on_smis); |
|
833 |
// Tag the result and store it in register eax. |
|
834 |
__ SmiTag(left); |
|
835 |
__ mov(eax, left); |
|
836 |
break; |
|
837 |
|
|
838 |
case Token::ADD: |
|
839 |
ASSERT(right.is(eax)); |
|
840 |
__ add(right, left); // Addition is commutative. |
|
841 |
__ j(overflow, &use_fp_on_smis); |
|
842 |
break; |
|
843 |
|
|
844 |
case Token::SUB: |
|
845 |
__ sub(left, right); |
|
846 |
__ j(overflow, &use_fp_on_smis); |
|
847 |
__ mov(eax, left); |
|
848 |
break; |
|
849 |
|
|
850 |
case Token::MUL: |
|
851 |
// If the smi tag is 0 we can just leave the tag on one operand. |
|
852 |
STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
|
853 |
// We can't revert the multiplication if the result is not a smi |
|
854 |
// so save the right operand. |
|
855 |
__ mov(ebx, right); |
|
856 |
// Remove tag from one of the operands (but keep sign). |
|
857 |
__ SmiUntag(right); |
|
858 |
// Do multiplication. |
|
859 |
__ imul(right, left); // Multiplication is commutative. |
|
860 |
__ j(overflow, &use_fp_on_smis); |
|
861 |
// Check for negative zero result. Use combined = left | right. |
|
862 |
__ NegativeZeroTest(right, combined, &use_fp_on_smis); |
|
863 |
break; |
|
864 |
|
|
865 |
case Token::DIV: |
|
866 |
// We can't revert the division if the result is not a smi so |
|
867 |
// save the left operand. |
|
868 |
__ mov(edi, left); |
|
869 |
// Check for 0 divisor. |
|
870 |
__ test(right, right); |
|
871 |
__ j(zero, &use_fp_on_smis); |
|
872 |
// Sign extend left into edx:eax. |
|
873 |
ASSERT(left.is(eax)); |
|
874 |
__ cdq(); |
|
875 |
// Divide edx:eax by right. |
|
876 |
__ idiv(right); |
|
877 |
// Check for the corner case of dividing the most negative smi by |
|
878 |
// -1. We cannot use the overflow flag, since it is not set by idiv |
|
879 |
// instruction. |
|
880 |
STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
|
881 |
__ cmp(eax, 0x40000000); |
|
882 |
__ j(equal, &use_fp_on_smis); |
|
883 |
// Check for negative zero result. Use combined = left | right. |
|
884 |
__ NegativeZeroTest(eax, combined, &use_fp_on_smis); |
|
885 |
// Check that the remainder is zero. |
|
886 |
__ test(edx, edx); |
|
887 |
__ j(not_zero, &use_fp_on_smis); |
|
888 |
// Tag the result and store it in register eax. |
|
889 |
__ SmiTag(eax); |
|
890 |
break; |
|
891 |
|
|
892 |
case Token::MOD: |
|
893 |
// Check for 0 divisor. |
|
894 |
__ test(right, right); |
|
895 |
__ j(zero, ¬_smis); |
|
896 |
|
|
897 |
// Sign extend left into edx:eax. |
|
898 |
ASSERT(left.is(eax)); |
|
899 |
__ cdq(); |
|
900 |
// Divide edx:eax by right. |
|
901 |
__ idiv(right); |
|
902 |
// Check for negative zero result. Use combined = left | right. |
|
903 |
__ NegativeZeroTest(edx, combined, slow); |
|
904 |
// Move remainder to register eax. |
|
905 |
__ mov(eax, edx); |
|
906 |
break; |
|
907 |
|
|
908 |
default: |
|
909 |
UNREACHABLE(); |
|
910 |
} |
|
911 |
|
|
912 |
// 5. Emit return of result in eax. Some operations have registers pushed. |
|
913 |
switch (op) { |
|
914 |
case Token::ADD: |
|
915 |
case Token::SUB: |
|
916 |
case Token::MUL: |
|
917 |
case Token::DIV: |
|
918 |
__ ret(0); |
|
919 |
break; |
|
920 |
case Token::MOD: |
|
921 |
case Token::BIT_OR: |
|
922 |
case Token::BIT_AND: |
|
923 |
case Token::BIT_XOR: |
|
924 |
case Token::SAR: |
|
925 |
case Token::SHL: |
|
926 |
case Token::SHR: |
|
927 |
__ ret(2 * kPointerSize); |
|
928 |
break; |
|
929 |
default: |
|
930 |
UNREACHABLE(); |
|
931 |
} |
|
932 |
|
|
933 |
// 6. For some operations emit inline code to perform floating point |
|
934 |
// operations on known smis (e.g., if the result of the operation |
|
935 |
// overflowed the smi range). |
|
936 |
if (allow_heapnumber_results == BinaryOpStub::NO_HEAPNUMBER_RESULTS) { |
|
937 |
__ bind(&use_fp_on_smis); |
|
938 |
switch (op) { |
|
939 |
// Undo the effects of some operations, and some register moves. |
|
940 |
case Token::SHL: |
|
941 |
// The arguments are saved on the stack, and only used from there. |
|
942 |
break; |
|
943 |
case Token::ADD: |
|
944 |
// Revert right = right + left. |
|
945 |
__ sub(right, left); |
|
946 |
break; |
|
947 |
case Token::SUB: |
|
948 |
// Revert left = left - right. |
|
949 |
__ add(left, right); |
|
950 |
break; |
|
951 |
case Token::MUL: |
|
952 |
// Right was clobbered but a copy is in ebx. |
|
953 |
__ mov(right, ebx); |
|
954 |
break; |
|
955 |
case Token::DIV: |
|
956 |
// Left was clobbered but a copy is in edi. Right is in ebx for |
|
957 |
// division. They should be in eax, ebx for jump to not_smi. |
|
958 |
__ mov(eax, edi); |
|
959 |
break; |
|
960 |
default: |
|
961 |
// No other operators jump to use_fp_on_smis. |
|
962 |
break; |
|
963 |
} |
|
964 |
__ jmp(¬_smis); |
|
965 |
} else { |
|
966 |
ASSERT(allow_heapnumber_results == BinaryOpStub::ALLOW_HEAPNUMBER_RESULTS); |
|
967 |
switch (op) { |
|
968 |
case Token::SHL: |
|
969 |
case Token::SHR: { |
|
970 |
Comment perform_float(masm, "-- Perform float operation on smis"); |
|
971 |
__ bind(&use_fp_on_smis); |
|
972 |
// Result we want is in left == edx, so we can put the allocated heap |
|
973 |
// number in eax. |
|
974 |
__ AllocateHeapNumber(eax, ecx, ebx, slow); |
|
975 |
// Store the result in the HeapNumber and return. |
|
976 |
// It's OK to overwrite the arguments on the stack because we |
|
977 |
// are about to return. |
|
978 |
if (op == Token::SHR) { |
|
979 |
__ mov(Operand(esp, 1 * kPointerSize), left); |
|
980 |
__ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); |
|
981 |
__ fild_d(Operand(esp, 1 * kPointerSize)); |
|
982 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
983 |
} else { |
|
984 |
ASSERT_EQ(Token::SHL, op); |
|
985 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
986 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
987 |
__ cvtsi2sd(xmm0, left); |
|
988 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
989 |
} else { |
|
990 |
__ mov(Operand(esp, 1 * kPointerSize), left); |
|
991 |
__ fild_s(Operand(esp, 1 * kPointerSize)); |
|
992 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
993 |
} |
|
994 |
} |
|
995 |
__ ret(2 * kPointerSize); |
|
996 |
break; |
|
997 |
} |
|
998 |
|
|
999 |
case Token::ADD: |
|
1000 |
case Token::SUB: |
|
1001 |
case Token::MUL: |
|
1002 |
case Token::DIV: { |
|
1003 |
Comment perform_float(masm, "-- Perform float operation on smis"); |
|
1004 |
__ bind(&use_fp_on_smis); |
|
1005 |
// Restore arguments to edx, eax. |
|
1006 |
switch (op) { |
|
1007 |
case Token::ADD: |
|
1008 |
// Revert right = right + left. |
|
1009 |
__ sub(right, left); |
|
1010 |
break; |
|
1011 |
case Token::SUB: |
|
1012 |
// Revert left = left - right. |
|
1013 |
__ add(left, right); |
|
1014 |
break; |
|
1015 |
case Token::MUL: |
|
1016 |
// Right was clobbered but a copy is in ebx. |
|
1017 |
__ mov(right, ebx); |
|
1018 |
break; |
|
1019 |
case Token::DIV: |
|
1020 |
// Left was clobbered but a copy is in edi. Right is in ebx for |
|
1021 |
// division. |
|
1022 |
__ mov(edx, edi); |
|
1023 |
__ mov(eax, right); |
|
1024 |
break; |
|
1025 |
default: UNREACHABLE(); |
|
1026 |
break; |
|
1027 |
} |
|
1028 |
__ AllocateHeapNumber(ecx, ebx, no_reg, slow); |
|
1029 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1030 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1031 |
FloatingPointHelper::LoadSSE2Smis(masm, ebx); |
|
1032 |
switch (op) { |
|
1033 |
case Token::ADD: __ addsd(xmm0, xmm1); break; |
|
1034 |
case Token::SUB: __ subsd(xmm0, xmm1); break; |
|
1035 |
case Token::MUL: __ mulsd(xmm0, xmm1); break; |
|
1036 |
case Token::DIV: __ divsd(xmm0, xmm1); break; |
|
1037 |
default: UNREACHABLE(); |
|
1038 |
} |
|
1039 |
__ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); |
|
1040 |
} else { // SSE2 not available, use FPU. |
|
1041 |
FloatingPointHelper::LoadFloatSmis(masm, ebx); |
|
1042 |
switch (op) { |
|
1043 |
case Token::ADD: __ faddp(1); break; |
|
1044 |
case Token::SUB: __ fsubp(1); break; |
|
1045 |
case Token::MUL: __ fmulp(1); break; |
|
1046 |
case Token::DIV: __ fdivp(1); break; |
|
1047 |
default: UNREACHABLE(); |
|
1048 |
} |
|
1049 |
__ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); |
|
1050 |
} |
|
1051 |
__ mov(eax, ecx); |
|
1052 |
__ ret(0); |
|
1053 |
break; |
|
1054 |
} |
|
1055 |
|
|
1056 |
default: |
|
1057 |
break; |
|
1058 |
} |
|
1059 |
} |
|
1060 |
|
|
1061 |
// 7. Non-smi operands, fall out to the non-smi code with the operands in |
|
1062 |
// edx and eax. |
|
1063 |
Comment done_comment(masm, "-- Enter non-smi code"); |
|
1064 |
__ bind(¬_smis); |
|
1065 |
switch (op) { |
|
1066 |
case Token::BIT_OR: |
|
1067 |
case Token::SHL: |
|
1068 |
case Token::SAR: |
|
1069 |
case Token::SHR: |
|
1070 |
// Right operand is saved in ecx and eax was destroyed by the smi |
|
1071 |
// check. |
|
1072 |
__ mov(eax, ecx); |
|
1073 |
break; |
|
1074 |
|
|
1075 |
case Token::DIV: |
|
1076 |
case Token::MOD: |
|
1077 |
// Operands are in eax, ebx at this point. |
|
1078 |
__ mov(edx, eax); |
|
1079 |
__ mov(eax, ebx); |
|
1080 |
break; |
|
1081 |
|
|
1082 |
default: |
|
1083 |
break; |
|
1084 |
} |
|
1085 |
} |
|
1086 |
|
|
1087 |
|
|
1088 |
void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
|
1089 |
Label right_arg_changed, call_runtime; |
|
1090 |
|
|
1091 |
switch (op_) { |
|
1092 |
case Token::ADD: |
|
1093 |
case Token::SUB: |
|
1094 |
case Token::MUL: |
|
1095 |
case Token::DIV: |
|
1096 |
break; |
|
1097 |
case Token::MOD: |
|
1098 |
case Token::BIT_OR: |
|
1099 |
case Token::BIT_AND: |
|
1100 |
case Token::BIT_XOR: |
|
1101 |
case Token::SAR: |
|
1102 |
case Token::SHL: |
|
1103 |
case Token::SHR: |
|
1104 |
GenerateRegisterArgsPush(masm); |
|
1105 |
break; |
|
1106 |
default: |
|
1107 |
UNREACHABLE(); |
|
1108 |
} |
|
1109 |
|
|
1110 |
if (op_ == Token::MOD && encoded_right_arg_.has_value) { |
|
1111 |
// It is guaranteed that the value will fit into a Smi, because if it |
|
1112 |
// didn't, we wouldn't be here, see BinaryOp_Patch. |
|
1113 |
__ cmp(eax, Immediate(Smi::FromInt(fixed_right_arg_value()))); |
|
1114 |
__ j(not_equal, &right_arg_changed); |
|
1115 |
} |
|
1116 |
|
|
1117 |
if (result_type_ == BinaryOpIC::UNINITIALIZED || |
|
1118 |
result_type_ == BinaryOpIC::SMI) { |
|
1119 |
BinaryOpStub_GenerateSmiCode( |
|
1120 |
masm, &call_runtime, NO_HEAPNUMBER_RESULTS, op_); |
|
1121 |
} else { |
|
1122 |
BinaryOpStub_GenerateSmiCode( |
|
1123 |
masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); |
|
1124 |
} |
|
1125 |
|
|
1126 |
// Code falls through if the result is not returned as either a smi or heap |
|
1127 |
// number. |
|
1128 |
__ bind(&right_arg_changed); |
|
1129 |
switch (op_) { |
|
1130 |
case Token::ADD: |
|
1131 |
case Token::SUB: |
|
1132 |
case Token::MUL: |
|
1133 |
case Token::DIV: |
|
1134 |
GenerateTypeTransition(masm); |
|
1135 |
break; |
|
1136 |
case Token::MOD: |
|
1137 |
case Token::BIT_OR: |
|
1138 |
case Token::BIT_AND: |
|
1139 |
case Token::BIT_XOR: |
|
1140 |
case Token::SAR: |
|
1141 |
case Token::SHL: |
|
1142 |
case Token::SHR: |
|
1143 |
GenerateTypeTransitionWithSavedArgs(masm); |
|
1144 |
break; |
|
1145 |
default: |
|
1146 |
UNREACHABLE(); |
|
1147 |
} |
|
1148 |
|
|
1149 |
__ bind(&call_runtime); |
|
1150 |
switch (op_) { |
|
1151 |
case Token::ADD: |
|
1152 |
case Token::SUB: |
|
1153 |
case Token::MUL: |
|
1154 |
case Token::DIV: |
|
1155 |
break; |
|
1156 |
case Token::MOD: |
|
1157 |
case Token::BIT_OR: |
|
1158 |
case Token::BIT_AND: |
|
1159 |
case Token::BIT_XOR: |
|
1160 |
case Token::SAR: |
|
1161 |
case Token::SHL: |
|
1162 |
case Token::SHR: |
|
1163 |
BinaryOpStub_GenerateRegisterArgsPop(masm); |
|
1164 |
break; |
|
1165 |
default: |
|
1166 |
UNREACHABLE(); |
|
1167 |
} |
|
1168 |
|
|
1169 |
{ |
|
1170 |
FrameScope scope(masm, StackFrame::INTERNAL); |
|
1171 |
__ push(edx); |
|
1172 |
__ push(eax); |
|
1173 |
GenerateCallRuntime(masm); |
|
1174 |
} |
|
1175 |
__ ret(0); |
|
1176 |
} |
|
1177 |
|
|
1178 |
|
|
1179 |
void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { |
|
1180 |
Label call_runtime; |
|
1181 |
ASSERT(left_type_ == BinaryOpIC::STRING && right_type_ == BinaryOpIC::STRING); |
|
1182 |
ASSERT(op_ == Token::ADD); |
|
1183 |
// If both arguments are strings, call the string add stub. |
|
1184 |
// Otherwise, do a transition. |
|
1185 |
|
|
1186 |
// Registers containing left and right operands respectively. |
|
1187 |
Register left = edx; |
|
1188 |
Register right = eax; |
|
1189 |
|
|
1190 |
// Test if left operand is a string. |
|
1191 |
__ JumpIfSmi(left, &call_runtime, Label::kNear); |
|
1192 |
__ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); |
|
1193 |
__ j(above_equal, &call_runtime, Label::kNear); |
|
1194 |
|
|
1195 |
// Test if right operand is a string. |
|
1196 |
__ JumpIfSmi(right, &call_runtime, Label::kNear); |
|
1197 |
__ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); |
|
1198 |
__ j(above_equal, &call_runtime, Label::kNear); |
|
1199 |
|
|
1200 |
StringAddStub string_add_stub( |
|
1201 |
(StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); |
|
1202 |
GenerateRegisterArgsPush(masm); |
|
1203 |
__ TailCallStub(&string_add_stub); |
|
1204 |
|
|
1205 |
__ bind(&call_runtime); |
|
1206 |
GenerateTypeTransition(masm); |
|
1207 |
} |
|
1208 |
|
|
1209 |
|
|
1210 |
static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, |
|
1211 |
Label* alloc_failure, |
|
1212 |
OverwriteMode mode); |
|
1213 |
|
|
1214 |
|
|
1215 |
// Input: |
|
1216 |
// edx: left operand (tagged) |
|
1217 |
// eax: right operand (tagged) |
|
1218 |
// Output: |
|
1219 |
// eax: result (tagged) |
|
1220 |
void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { |
|
1221 |
Label call_runtime; |
|
1222 |
ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); |
|
1223 |
|
|
1224 |
// Floating point case. |
|
1225 |
switch (op_) { |
|
1226 |
case Token::ADD: |
|
1227 |
case Token::SUB: |
|
1228 |
case Token::MUL: |
|
1229 |
case Token::DIV: |
|
1230 |
case Token::MOD: { |
|
1231 |
Label not_floats, not_int32, right_arg_changed; |
|
1232 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1233 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1234 |
// It could be that only SMIs have been seen at either the left |
|
1235 |
// or the right operand. For precise type feedback, patch the IC |
|
1236 |
// again if this changes. |
|
1237 |
// In theory, we would need the same check in the non-SSE2 case, |
|
1238 |
// but since we don't support Crankshaft on such hardware we can |
|
1239 |
// afford not to care about precise type feedback. |
|
1240 |
if (left_type_ == BinaryOpIC::SMI) { |
|
1241 |
__ JumpIfNotSmi(edx, ¬_int32); |
|
1242 |
} |
|
1243 |
if (right_type_ == BinaryOpIC::SMI) { |
|
1244 |
__ JumpIfNotSmi(eax, ¬_int32); |
|
1245 |
} |
|
1246 |
FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
|
1247 |
FloatingPointHelper::CheckSSE2OperandIsInt32( |
|
1248 |
masm, ¬_int32, xmm0, ebx, ecx, xmm2); |
|
1249 |
FloatingPointHelper::CheckSSE2OperandIsInt32( |
|
1250 |
masm, ¬_int32, xmm1, edi, ecx, xmm2); |
|
1251 |
if (op_ == Token::MOD) { |
|
1252 |
if (encoded_right_arg_.has_value) { |
|
1253 |
__ cmp(edi, Immediate(fixed_right_arg_value())); |
|
1254 |
__ j(not_equal, &right_arg_changed); |
|
1255 |
} |
|
1256 |
GenerateRegisterArgsPush(masm); |
|
1257 |
__ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); |
|
1258 |
} else { |
|
1259 |
switch (op_) { |
|
1260 |
case Token::ADD: __ addsd(xmm0, xmm1); break; |
|
1261 |
case Token::SUB: __ subsd(xmm0, xmm1); break; |
|
1262 |
case Token::MUL: __ mulsd(xmm0, xmm1); break; |
|
1263 |
case Token::DIV: __ divsd(xmm0, xmm1); break; |
|
1264 |
default: UNREACHABLE(); |
|
1265 |
} |
|
1266 |
// Check result type if it is currently Int32. |
|
1267 |
if (result_type_ <= BinaryOpIC::INT32) { |
|
1268 |
FloatingPointHelper::CheckSSE2OperandIsInt32( |
|
1269 |
masm, ¬_int32, xmm0, ecx, ecx, xmm2); |
|
1270 |
} |
|
1271 |
BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); |
|
1272 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
1273 |
__ ret(0); |
|
1274 |
} |
|
1275 |
} else { // SSE2 not available, use FPU. |
|
1276 |
FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |
|
1277 |
FloatingPointHelper::LoadFloatOperands( |
|
1278 |
masm, |
|
1279 |
ecx, |
|
1280 |
FloatingPointHelper::ARGS_IN_REGISTERS); |
|
1281 |
if (op_ == Token::MOD) { |
|
1282 |
// The operands are now on the FPU stack, but we don't need them. |
|
1283 |
__ fstp(0); |
|
1284 |
__ fstp(0); |
|
1285 |
GenerateRegisterArgsPush(masm); |
|
1286 |
__ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); |
|
1287 |
} else { |
|
1288 |
switch (op_) { |
|
1289 |
case Token::ADD: __ faddp(1); break; |
|
1290 |
case Token::SUB: __ fsubp(1); break; |
|
1291 |
case Token::MUL: __ fmulp(1); break; |
|
1292 |
case Token::DIV: __ fdivp(1); break; |
|
1293 |
default: UNREACHABLE(); |
|
1294 |
} |
|
1295 |
Label after_alloc_failure; |
|
1296 |
BinaryOpStub_GenerateHeapResultAllocation( |
|
1297 |
masm, &after_alloc_failure, mode_); |
|
1298 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
1299 |
__ ret(0); |
|
1300 |
__ bind(&after_alloc_failure); |
|
1301 |
__ fstp(0); // Pop FPU stack before calling runtime. |
|
1302 |
__ jmp(&call_runtime); |
|
1303 |
} |
|
1304 |
} |
|
1305 |
|
|
1306 |
__ bind(¬_floats); |
|
1307 |
__ bind(¬_int32); |
|
1308 |
__ bind(&right_arg_changed); |
|
1309 |
GenerateTypeTransition(masm); |
|
1310 |
break; |
|
1311 |
} |
|
1312 |
|
|
1313 |
case Token::BIT_OR: |
|
1314 |
case Token::BIT_AND: |
|
1315 |
case Token::BIT_XOR: |
|
1316 |
case Token::SAR: |
|
1317 |
case Token::SHL: |
|
1318 |
case Token::SHR: { |
|
1319 |
GenerateRegisterArgsPush(masm); |
|
1320 |
Label not_floats; |
|
1321 |
Label not_int32; |
|
1322 |
Label non_smi_result; |
|
1323 |
bool use_sse3 = platform_specific_bit_; |
|
1324 |
FloatingPointHelper::LoadUnknownsAsIntegers( |
|
1325 |
masm, use_sse3, left_type_, right_type_, ¬_floats); |
|
1326 |
switch (op_) { |
|
1327 |
case Token::BIT_OR: __ or_(eax, ecx); break; |
|
1328 |
case Token::BIT_AND: __ and_(eax, ecx); break; |
|
1329 |
case Token::BIT_XOR: __ xor_(eax, ecx); break; |
|
1330 |
case Token::SAR: __ sar_cl(eax); break; |
|
1331 |
case Token::SHL: __ shl_cl(eax); break; |
|
1332 |
case Token::SHR: __ shr_cl(eax); break; |
|
1333 |
default: UNREACHABLE(); |
|
1334 |
} |
|
1335 |
if (op_ == Token::SHR) { |
|
1336 |
// Check if result is non-negative and fits in a smi. |
|
1337 |
__ test(eax, Immediate(0xc0000000)); |
|
1338 |
__ j(not_zero, &call_runtime); |
|
1339 |
} else { |
|
1340 |
// Check if result fits in a smi. |
|
1341 |
__ cmp(eax, 0xc0000000); |
|
1342 |
__ j(negative, &non_smi_result, Label::kNear); |
|
1343 |
} |
|
1344 |
// Tag smi result and return. |
|
1345 |
__ SmiTag(eax); |
|
1346 |
__ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. |
|
1347 |
|
|
1348 |
// All ops except SHR return a signed int32 that we load in |
|
1349 |
// a HeapNumber. |
|
1350 |
if (op_ != Token::SHR) { |
|
1351 |
__ bind(&non_smi_result); |
|
1352 |
// Allocate a heap number if needed. |
|
1353 |
__ mov(ebx, eax); // ebx: result |
|
1354 |
Label skip_allocation; |
|
1355 |
switch (mode_) { |
|
1356 |
case OVERWRITE_LEFT: |
|
1357 |
case OVERWRITE_RIGHT: |
|
1358 |
// If the operand was an object, we skip the |
|
1359 |
// allocation of a heap number. |
|
1360 |
__ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
|
1361 |
1 * kPointerSize : 2 * kPointerSize)); |
|
1362 |
__ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
|
1363 |
// Fall through! |
|
1364 |
case NO_OVERWRITE: |
|
1365 |
__ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
|
1366 |
__ bind(&skip_allocation); |
|
1367 |
break; |
|
1368 |
default: UNREACHABLE(); |
|
1369 |
} |
|
1370 |
// Store the result in the HeapNumber and return. |
|
1371 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1372 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1373 |
__ cvtsi2sd(xmm0, ebx); |
|
1374 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
1375 |
} else { |
|
1376 |
__ mov(Operand(esp, 1 * kPointerSize), ebx); |
|
1377 |
__ fild_s(Operand(esp, 1 * kPointerSize)); |
|
1378 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
1379 |
} |
|
1380 |
__ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. |
|
1381 |
} |
|
1382 |
|
|
1383 |
__ bind(¬_floats); |
|
1384 |
__ bind(¬_int32); |
|
1385 |
GenerateTypeTransitionWithSavedArgs(masm); |
|
1386 |
break; |
|
1387 |
} |
|
1388 |
default: UNREACHABLE(); break; |
|
1389 |
} |
|
1390 |
|
|
1391 |
// If an allocation fails, or SHR hits a hard case, use the runtime system to |
|
1392 |
// get the correct result. |
|
1393 |
__ bind(&call_runtime); |
|
1394 |
|
|
1395 |
switch (op_) { |
|
1396 |
case Token::ADD: |
|
1397 |
case Token::SUB: |
|
1398 |
case Token::MUL: |
|
1399 |
case Token::DIV: |
|
1400 |
break; |
|
1401 |
case Token::MOD: |
|
1402 |
return; // Handled above. |
|
1403 |
case Token::BIT_OR: |
|
1404 |
case Token::BIT_AND: |
|
1405 |
case Token::BIT_XOR: |
|
1406 |
case Token::SAR: |
|
1407 |
case Token::SHL: |
|
1408 |
case Token::SHR: |
|
1409 |
BinaryOpStub_GenerateRegisterArgsPop(masm); |
|
1410 |
break; |
|
1411 |
default: |
|
1412 |
UNREACHABLE(); |
|
1413 |
} |
|
1414 |
|
|
1415 |
{ |
|
1416 |
FrameScope scope(masm, StackFrame::INTERNAL); |
|
1417 |
__ push(edx); |
|
1418 |
__ push(eax); |
|
1419 |
GenerateCallRuntime(masm); |
|
1420 |
} |
|
1421 |
__ ret(0); |
|
1422 |
} |
|
1423 |
|
|
1424 |
|
|
1425 |
void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { |
|
1426 |
if (op_ == Token::ADD) { |
|
1427 |
// Handle string addition here, because it is the only operation |
|
1428 |
// that does not do a ToNumber conversion on the operands. |
|
1429 |
GenerateAddStrings(masm); |
|
1430 |
} |
|
1431 |
|
|
1432 |
Factory* factory = masm->isolate()->factory(); |
|
1433 |
|
|
1434 |
// Convert odd ball arguments to numbers. |
|
1435 |
Label check, done; |
|
1436 |
__ cmp(edx, factory->undefined_value()); |
|
1437 |
__ j(not_equal, &check, Label::kNear); |
|
1438 |
if (Token::IsBitOp(op_)) { |
|
1439 |
__ xor_(edx, edx); |
|
1440 |
} else { |
|
1441 |
__ mov(edx, Immediate(factory->nan_value())); |
|
1442 |
} |
|
1443 |
__ jmp(&done, Label::kNear); |
|
1444 |
__ bind(&check); |
|
1445 |
__ cmp(eax, factory->undefined_value()); |
|
1446 |
__ j(not_equal, &done, Label::kNear); |
|
1447 |
if (Token::IsBitOp(op_)) { |
|
1448 |
__ xor_(eax, eax); |
|
1449 |
} else { |
|
1450 |
__ mov(eax, Immediate(factory->nan_value())); |
|
1451 |
} |
|
1452 |
__ bind(&done); |
|
1453 |
|
|
1454 |
GenerateNumberStub(masm); |
|
1455 |
} |
|
1456 |
|
|
1457 |
|
|
1458 |
void BinaryOpStub::GenerateNumberStub(MacroAssembler* masm) { |
|
1459 |
Label call_runtime; |
|
1460 |
|
|
1461 |
// Floating point case. |
|
1462 |
switch (op_) { |
|
1463 |
case Token::ADD: |
|
1464 |
case Token::SUB: |
|
1465 |
case Token::MUL: |
|
1466 |
case Token::DIV: { |
|
1467 |
Label not_floats; |
|
1468 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1469 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1470 |
|
|
1471 |
// It could be that only SMIs have been seen at either the left |
|
1472 |
// or the right operand. For precise type feedback, patch the IC |
|
1473 |
// again if this changes. |
|
1474 |
// In theory, we would need the same check in the non-SSE2 case, |
|
1475 |
// but since we don't support Crankshaft on such hardware we can |
|
1476 |
// afford not to care about precise type feedback. |
|
1477 |
if (left_type_ == BinaryOpIC::SMI) { |
|
1478 |
__ JumpIfNotSmi(edx, ¬_floats); |
|
1479 |
} |
|
1480 |
if (right_type_ == BinaryOpIC::SMI) { |
|
1481 |
__ JumpIfNotSmi(eax, ¬_floats); |
|
1482 |
} |
|
1483 |
FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
|
1484 |
if (left_type_ == BinaryOpIC::INT32) { |
|
1485 |
FloatingPointHelper::CheckSSE2OperandIsInt32( |
|
1486 |
masm, ¬_floats, xmm0, ecx, ecx, xmm2); |
|
1487 |
} |
|
1488 |
if (right_type_ == BinaryOpIC::INT32) { |
|
1489 |
FloatingPointHelper::CheckSSE2OperandIsInt32( |
|
1490 |
masm, ¬_floats, xmm1, ecx, ecx, xmm2); |
|
1491 |
} |
|
1492 |
|
|
1493 |
switch (op_) { |
|
1494 |
case Token::ADD: __ addsd(xmm0, xmm1); break; |
|
1495 |
case Token::SUB: __ subsd(xmm0, xmm1); break; |
|
1496 |
case Token::MUL: __ mulsd(xmm0, xmm1); break; |
|
1497 |
case Token::DIV: __ divsd(xmm0, xmm1); break; |
|
1498 |
default: UNREACHABLE(); |
|
1499 |
} |
|
1500 |
BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); |
|
1501 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
1502 |
__ ret(0); |
|
1503 |
} else { // SSE2 not available, use FPU. |
|
1504 |
FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |
|
1505 |
FloatingPointHelper::LoadFloatOperands( |
|
1506 |
masm, |
|
1507 |
ecx, |
|
1508 |
FloatingPointHelper::ARGS_IN_REGISTERS); |
|
1509 |
switch (op_) { |
|
1510 |
case Token::ADD: __ faddp(1); break; |
|
1511 |
case Token::SUB: __ fsubp(1); break; |
|
1512 |
case Token::MUL: __ fmulp(1); break; |
|
1513 |
case Token::DIV: __ fdivp(1); break; |
|
1514 |
default: UNREACHABLE(); |
|
1515 |
} |
|
1516 |
Label after_alloc_failure; |
|
1517 |
BinaryOpStub_GenerateHeapResultAllocation( |
|
1518 |
masm, &after_alloc_failure, mode_); |
|
1519 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
1520 |
__ ret(0); |
|
1521 |
__ bind(&after_alloc_failure); |
|
1522 |
__ fstp(0); // Pop FPU stack before calling runtime. |
|
1523 |
__ jmp(&call_runtime); |
|
1524 |
} |
|
1525 |
|
|
1526 |
__ bind(¬_floats); |
|
1527 |
GenerateTypeTransition(masm); |
|
1528 |
break; |
|
1529 |
} |
|
1530 |
|
|
1531 |
case Token::MOD: { |
|
1532 |
// For MOD we go directly to runtime in the non-smi case. |
|
1533 |
break; |
|
1534 |
} |
|
1535 |
case Token::BIT_OR: |
|
1536 |
case Token::BIT_AND: |
|
1537 |
case Token::BIT_XOR: |
|
1538 |
case Token::SAR: |
|
1539 |
case Token::SHL: |
|
1540 |
case Token::SHR: { |
|
1541 |
GenerateRegisterArgsPush(masm); |
|
1542 |
Label not_floats; |
|
1543 |
Label non_smi_result; |
|
1544 |
// We do not check the input arguments here, as any value is |
|
1545 |
// unconditionally truncated to an int32 anyway. To get the |
|
1546 |
// right optimized code, int32 type feedback is just right. |
|
1547 |
bool use_sse3 = platform_specific_bit_; |
|
1548 |
FloatingPointHelper::LoadUnknownsAsIntegers( |
|
1549 |
masm, use_sse3, left_type_, right_type_, ¬_floats); |
|
1550 |
switch (op_) { |
|
1551 |
case Token::BIT_OR: __ or_(eax, ecx); break; |
|
1552 |
case Token::BIT_AND: __ and_(eax, ecx); break; |
|
1553 |
case Token::BIT_XOR: __ xor_(eax, ecx); break; |
|
1554 |
case Token::SAR: __ sar_cl(eax); break; |
|
1555 |
case Token::SHL: __ shl_cl(eax); break; |
|
1556 |
case Token::SHR: __ shr_cl(eax); break; |
|
1557 |
default: UNREACHABLE(); |
|
1558 |
} |
|
1559 |
if (op_ == Token::SHR) { |
|
1560 |
// Check if result is non-negative and fits in a smi. |
|
1561 |
__ test(eax, Immediate(0xc0000000)); |
|
1562 |
__ j(not_zero, &call_runtime); |
|
1563 |
} else { |
|
1564 |
// Check if result fits in a smi. |
|
1565 |
__ cmp(eax, 0xc0000000); |
|
1566 |
__ j(negative, &non_smi_result, Label::kNear); |
|
1567 |
} |
|
1568 |
// Tag smi result and return. |
|
1569 |
__ SmiTag(eax); |
|
1570 |
__ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. |
|
1571 |
|
|
1572 |
// All ops except SHR return a signed int32 that we load in |
|
1573 |
// a HeapNumber. |
|
1574 |
if (op_ != Token::SHR) { |
|
1575 |
__ bind(&non_smi_result); |
|
1576 |
// Allocate a heap number if needed. |
|
1577 |
__ mov(ebx, eax); // ebx: result |
|
1578 |
Label skip_allocation; |
|
1579 |
switch (mode_) { |
|
1580 |
case OVERWRITE_LEFT: |
|
1581 |
case OVERWRITE_RIGHT: |
|
1582 |
// If the operand was an object, we skip the |
|
1583 |
// allocation of a heap number. |
|
1584 |
__ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
|
1585 |
1 * kPointerSize : 2 * kPointerSize)); |
|
1586 |
__ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
|
1587 |
// Fall through! |
|
1588 |
case NO_OVERWRITE: |
|
1589 |
__ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
|
1590 |
__ bind(&skip_allocation); |
|
1591 |
break; |
|
1592 |
default: UNREACHABLE(); |
|
1593 |
} |
|
1594 |
// Store the result in the HeapNumber and return. |
|
1595 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1596 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1597 |
__ cvtsi2sd(xmm0, ebx); |
|
1598 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
1599 |
} else { |
|
1600 |
__ mov(Operand(esp, 1 * kPointerSize), ebx); |
|
1601 |
__ fild_s(Operand(esp, 1 * kPointerSize)); |
|
1602 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
1603 |
} |
|
1604 |
__ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. |
|
1605 |
} |
|
1606 |
|
|
1607 |
__ bind(¬_floats); |
|
1608 |
GenerateTypeTransitionWithSavedArgs(masm); |
|
1609 |
break; |
|
1610 |
} |
|
1611 |
default: UNREACHABLE(); break; |
|
1612 |
} |
|
1613 |
|
|
1614 |
// If an allocation fails, or SHR or MOD hit a hard case, |
|
1615 |
// use the runtime system to get the correct result. |
|
1616 |
__ bind(&call_runtime); |
|
1617 |
|
|
1618 |
switch (op_) { |
|
1619 |
case Token::ADD: |
|
1620 |
case Token::SUB: |
|
1621 |
case Token::MUL: |
|
1622 |
case Token::DIV: |
|
1623 |
case Token::MOD: |
|
1624 |
break; |
|
1625 |
case Token::BIT_OR: |
|
1626 |
case Token::BIT_AND: |
|
1627 |
case Token::BIT_XOR: |
|
1628 |
case Token::SAR: |
|
1629 |
case Token::SHL: |
|
1630 |
case Token::SHR: |
|
1631 |
BinaryOpStub_GenerateRegisterArgsPop(masm); |
|
1632 |
break; |
|
1633 |
default: |
|
1634 |
UNREACHABLE(); |
|
1635 |
} |
|
1636 |
|
|
1637 |
{ |
|
1638 |
FrameScope scope(masm, StackFrame::INTERNAL); |
|
1639 |
__ push(edx); |
|
1640 |
__ push(eax); |
|
1641 |
GenerateCallRuntime(masm); |
|
1642 |
} |
|
1643 |
__ ret(0); |
|
1644 |
} |
|
1645 |
|
|
1646 |
|
|
1647 |
void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { |
|
1648 |
Label call_runtime; |
|
1649 |
|
|
1650 |
Counters* counters = masm->isolate()->counters(); |
|
1651 |
__ IncrementCounter(counters->generic_binary_stub_calls(), 1); |
|
1652 |
|
|
1653 |
switch (op_) { |
|
1654 |
case Token::ADD: |
|
1655 |
case Token::SUB: |
|
1656 |
case Token::MUL: |
|
1657 |
case Token::DIV: |
|
1658 |
break; |
|
1659 |
case Token::MOD: |
|
1660 |
case Token::BIT_OR: |
|
1661 |
case Token::BIT_AND: |
|
1662 |
case Token::BIT_XOR: |
|
1663 |
case Token::SAR: |
|
1664 |
case Token::SHL: |
|
1665 |
case Token::SHR: |
|
1666 |
GenerateRegisterArgsPush(masm); |
|
1667 |
break; |
|
1668 |
default: |
|
1669 |
UNREACHABLE(); |
|
1670 |
} |
|
1671 |
|
|
1672 |
BinaryOpStub_GenerateSmiCode( |
|
1673 |
masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS, op_); |
|
1674 |
|
|
1675 |
// Floating point case. |
|
1676 |
switch (op_) { |
|
1677 |
case Token::ADD: |
|
1678 |
case Token::SUB: |
|
1679 |
case Token::MUL: |
|
1680 |
case Token::DIV: { |
|
1681 |
Label not_floats; |
|
1682 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1683 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1684 |
FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
|
1685 |
|
|
1686 |
switch (op_) { |
|
1687 |
case Token::ADD: __ addsd(xmm0, xmm1); break; |
|
1688 |
case Token::SUB: __ subsd(xmm0, xmm1); break; |
|
1689 |
case Token::MUL: __ mulsd(xmm0, xmm1); break; |
|
1690 |
case Token::DIV: __ divsd(xmm0, xmm1); break; |
|
1691 |
default: UNREACHABLE(); |
|
1692 |
} |
|
1693 |
BinaryOpStub_GenerateHeapResultAllocation(masm, &call_runtime, mode_); |
|
1694 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
1695 |
__ ret(0); |
|
1696 |
} else { // SSE2 not available, use FPU. |
|
1697 |
FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); |
|
1698 |
FloatingPointHelper::LoadFloatOperands( |
|
1699 |
masm, |
|
1700 |
ecx, |
|
1701 |
FloatingPointHelper::ARGS_IN_REGISTERS); |
|
1702 |
switch (op_) { |
|
1703 |
case Token::ADD: __ faddp(1); break; |
|
1704 |
case Token::SUB: __ fsubp(1); break; |
|
1705 |
case Token::MUL: __ fmulp(1); break; |
|
1706 |
case Token::DIV: __ fdivp(1); break; |
|
1707 |
default: UNREACHABLE(); |
|
1708 |
} |
|
1709 |
Label after_alloc_failure; |
|
1710 |
BinaryOpStub_GenerateHeapResultAllocation( |
|
1711 |
masm, &after_alloc_failure, mode_); |
|
1712 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
1713 |
__ ret(0); |
|
1714 |
__ bind(&after_alloc_failure); |
|
1715 |
__ fstp(0); // Pop FPU stack before calling runtime. |
|
1716 |
__ jmp(&call_runtime); |
|
1717 |
} |
|
1718 |
__ bind(¬_floats); |
|
1719 |
break; |
|
1720 |
} |
|
1721 |
case Token::MOD: { |
|
1722 |
// For MOD we go directly to runtime in the non-smi case. |
|
1723 |
break; |
|
1724 |
} |
|
1725 |
case Token::BIT_OR: |
|
1726 |
case Token::BIT_AND: |
|
1727 |
case Token::BIT_XOR: |
|
1728 |
case Token::SAR: |
|
1729 |
case Token::SHL: |
|
1730 |
case Token::SHR: { |
|
1731 |
Label non_smi_result; |
|
1732 |
bool use_sse3 = platform_specific_bit_; |
|
1733 |
FloatingPointHelper::LoadUnknownsAsIntegers(masm, |
|
1734 |
use_sse3, |
|
1735 |
BinaryOpIC::GENERIC, |
|
1736 |
BinaryOpIC::GENERIC, |
|
1737 |
&call_runtime); |
|
1738 |
switch (op_) { |
|
1739 |
case Token::BIT_OR: __ or_(eax, ecx); break; |
|
1740 |
case Token::BIT_AND: __ and_(eax, ecx); break; |
|
1741 |
case Token::BIT_XOR: __ xor_(eax, ecx); break; |
|
1742 |
case Token::SAR: __ sar_cl(eax); break; |
|
1743 |
case Token::SHL: __ shl_cl(eax); break; |
|
1744 |
case Token::SHR: __ shr_cl(eax); break; |
|
1745 |
default: UNREACHABLE(); |
|
1746 |
} |
|
1747 |
if (op_ == Token::SHR) { |
|
1748 |
// Check if result is non-negative and fits in a smi. |
|
1749 |
__ test(eax, Immediate(0xc0000000)); |
|
1750 |
__ j(not_zero, &call_runtime); |
|
1751 |
} else { |
|
1752 |
// Check if result fits in a smi. |
|
1753 |
__ cmp(eax, 0xc0000000); |
|
1754 |
__ j(negative, &non_smi_result, Label::kNear); |
|
1755 |
} |
|
1756 |
// Tag smi result and return. |
|
1757 |
__ SmiTag(eax); |
|
1758 |
__ ret(2 * kPointerSize); // Drop the arguments from the stack. |
|
1759 |
|
|
1760 |
// All ops except SHR return a signed int32 that we load in |
|
1761 |
// a HeapNumber. |
|
1762 |
if (op_ != Token::SHR) { |
|
1763 |
__ bind(&non_smi_result); |
|
1764 |
// Allocate a heap number if needed. |
|
1765 |
__ mov(ebx, eax); // ebx: result |
|
1766 |
Label skip_allocation; |
|
1767 |
switch (mode_) { |
|
1768 |
case OVERWRITE_LEFT: |
|
1769 |
case OVERWRITE_RIGHT: |
|
1770 |
// If the operand was an object, we skip the |
|
1771 |
// allocation of a heap number. |
|
1772 |
__ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
|
1773 |
1 * kPointerSize : 2 * kPointerSize)); |
|
1774 |
__ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
|
1775 |
// Fall through! |
|
1776 |
case NO_OVERWRITE: |
|
1777 |
__ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
|
1778 |
__ bind(&skip_allocation); |
|
1779 |
break; |
|
1780 |
default: UNREACHABLE(); |
|
1781 |
} |
|
1782 |
// Store the result in the HeapNumber and return. |
|
1783 |
if (CpuFeatures::IsSupported(SSE2)) { |
|
1784 |
CpuFeatureScope use_sse2(masm, SSE2); |
|
1785 |
__ cvtsi2sd(xmm0, ebx); |
|
1786 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
|
1787 |
} else { |
|
1788 |
__ mov(Operand(esp, 1 * kPointerSize), ebx); |
|
1789 |
__ fild_s(Operand(esp, 1 * kPointerSize)); |
|
1790 |
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
|
1791 |
} |
|
1792 |
__ ret(2 * kPointerSize); |
|
1793 |
} |
|
1794 |
break; |
|
1795 |
} |
|
1796 |
default: UNREACHABLE(); break; |
|
1797 |
} |
|
1798 |
|
|
1799 |
// If all else fails, use the runtime system to get the correct |
|
1800 |
// result. |
|
1801 |
__ bind(&call_runtime); |
|
1802 |
switch (op_) { |
|
1803 |
case Token::ADD: |
|
1804 |
GenerateAddStrings(masm); |
|
1805 |
// Fall through. |
|
1806 |
case Token::SUB: |
|
1807 |
case Token::MUL: |
|
1808 |
case Token::DIV: |
|
1809 |
break; |
|
1810 |
case Token::MOD: |
|
1811 |
case Token::BIT_OR: |
|
1812 |
case Token::BIT_AND: |
|
1813 |
case Token::BIT_XOR: |
|
1814 |
case Token::SAR: |
|
1815 |
case Token::SHL: |
|
1816 |
case Token::SHR: |
|
1817 |
BinaryOpStub_GenerateRegisterArgsPop(masm); |
|
1818 |
break; |
|
1819 |
default: |
|
1820 |
UNREACHABLE(); |
|
1821 |
} |
|
1822 |
|
|
1823 |
{ |
|
1824 |
FrameScope scope(masm, StackFrame::INTERNAL); |
|
1825 |
__ push(edx); |
|
1826 |
__ push(eax); |
|
1827 |
GenerateCallRuntime(masm); |
|
1828 |
} |
|
1829 |
__ ret(0); |
|
1830 |
} |
|
1831 |
|
|
1832 |
|
|
1833 |
void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { |
|
1834 |
ASSERT(op_ == Token::ADD); |
|
1835 |
Label left_not_string, call_runtime; |
|
1836 |
|
|
1837 |
// Registers containing left and right operands respectively. |
|
1838 |
Register left = edx; |
|
1839 |
Register right = eax; |
|
1840 |
|
|
1841 |
// Test if left operand is a string. |
|
1842 |
__ JumpIfSmi(left, &left_not_string, Label::kNear); |
|
1843 |
__ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); |
|
1844 |
__ j(above_equal, &left_not_string, Label::kNear); |
|
1845 |
|
|
1846 |
StringAddStub string_add_left_stub( |
|
1847 |
(StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); |
|
1848 |
GenerateRegisterArgsPush(masm); |
|
1849 |
__ TailCallStub(&string_add_left_stub); |
|
1850 |
|
|
1851 |
// Left operand is not a string, test right. |
|
1852 |
__ bind(&left_not_string); |
|
1853 |
__ JumpIfSmi(right, &call_runtime, Label::kNear); |
|
1854 |
__ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); |
|
1855 |
__ j(above_equal, &call_runtime, Label::kNear); |
|
1856 |
|
|
1857 |
StringAddStub string_add_right_stub( |
|
1858 |
(StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); |
|
1859 |
GenerateRegisterArgsPush(masm); |
|
1860 |
__ TailCallStub(&string_add_right_stub); |
|
1861 |
|
|
1862 |
// Neither argument is a string. |
|
1863 |
__ bind(&call_runtime); |
|
1864 |
} |
|
1865 |
|
|
1866 |
|
|
1867 |
static void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, |
|
1868 |
Label* alloc_failure, |
|
1869 |
OverwriteMode mode) { |
|
1870 |
Label skip_allocation; |
|
1871 |
switch (mode) { |
|
1872 |
case OVERWRITE_LEFT: { |
|
1873 |
// If the argument in edx is already an object, we skip the |
|
1874 |
// allocation of a heap number. |
|
1875 |
__ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); |
|
1876 |
// Allocate a heap number for the result. Keep eax and edx intact |
|
1877 |
// for the possible runtime call. |
|
1878 |
__ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
|
1879 |
// Now edx can be overwritten losing one of the arguments as we are |
|
1880 |
// now done and will not need it any more. |
|
1881 |
__ mov(edx, ebx); |
|
1882 |
__ bind(&skip_allocation); |
|
1883 |
// Use object in edx as a result holder |
|
1884 |
__ mov(eax, edx); |
|
1885 |
break; |
|
1886 |
} |
|
1887 |
case OVERWRITE_RIGHT: |
|
1888 |
// If the argument in eax is already an object, we skip the |
|
1889 |
// allocation of a heap number. |
|
1890 |
__ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); |
|
1891 |
// Fall through! |
|
1892 |
case NO_OVERWRITE: |
|
1893 |
// Allocate a heap number for the result. Keep eax and edx intact |
|
1894 |
// for the possible runtime call. |
|
1895 |
__ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); |
|
1896 |
// Now eax can be overwritten losing one of the arguments as we are |
|
1897 |
// now done and will not need it any more. |
|
1898 |
__ mov(eax, ebx); |
|
1899 |
__ bind(&skip_allocation); |
|
1900 |
break; |
|
1901 |
default: UNREACHABLE(); |
|
1902 |
} |
|
1903 |
} |
|
1904 |
|
|
1905 |
|
|
1906 |
void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
|
1907 |
__ pop(ecx); |
|
1908 |
__ push(edx); |
|
1909 |
__ push(eax); |
|
1910 |
__ push(ecx); |
|
1911 |
} |
|
1912 |
|
|
1913 |
|
|
1914 | 651 |
void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
1915 | 652 |
// TAGGED case: |
1916 | 653 |
// Input: |
... | ... | |
2034 | 771 |
__ ret(kPointerSize); |
2035 | 772 |
} else { // UNTAGGED. |
2036 | 773 |
CpuFeatureScope scope(masm, SSE2); |
2037 |
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
|
774 |
__ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
|
2038 | 775 |
__ Ret(); |
2039 | 776 |
} |
2040 | 777 |
|
... | ... | |
2049 | 786 |
CpuFeatureScope scope(masm, SSE2); |
2050 | 787 |
__ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); |
2051 | 788 |
__ sub(esp, Immediate(kDoubleSize)); |
2052 |
__ movdbl(Operand(esp, 0), xmm1);
|
|
789 |
__ movsd(Operand(esp, 0), xmm1);
|
|
2053 | 790 |
__ fld_d(Operand(esp, 0)); |
2054 | 791 |
__ add(esp, Immediate(kDoubleSize)); |
2055 | 792 |
} |
... | ... | |
2062 | 799 |
__ ret(kPointerSize); |
2063 | 800 |
} else { // UNTAGGED. |
2064 | 801 |
CpuFeatureScope scope(masm, SSE2); |
2065 |
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
|
802 |
__ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
|
2066 | 803 |
__ Ret(); |
2067 | 804 |
|
2068 | 805 |
// Skip cache and return answer directly, only in untagged case. |
2069 | 806 |
__ bind(&skip_cache); |
2070 | 807 |
__ sub(esp, Immediate(kDoubleSize)); |
2071 |
__ movdbl(Operand(esp, 0), xmm1);
|
|
808 |
__ movsd(Operand(esp, 0), xmm1);
|
|
2072 | 809 |
__ fld_d(Operand(esp, 0)); |
2073 | 810 |
GenerateOperation(masm, type_); |
2074 | 811 |
__ fstp_d(Operand(esp, 0)); |
2075 |
__ movdbl(xmm1, Operand(esp, 0));
|
|
812 |
__ movsd(xmm1, Operand(esp, 0));
|
|
2076 | 813 |
__ add(esp, Immediate(kDoubleSize)); |
2077 | 814 |
// We return the value in xmm1 without adding it to the cache, but |
2078 | 815 |
// we cause a scavenging GC so that future allocations will succeed. |
... | ... | |
2098 | 835 |
__ bind(&runtime_call_clear_stack); |
2099 | 836 |
__ bind(&runtime_call); |
2100 | 837 |
__ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); |
2101 |
__ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
|
|
838 |
__ movsd(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
|
|
2102 | 839 |
{ |
2103 | 840 |
FrameScope scope(masm, StackFrame::INTERNAL); |
2104 | 841 |
__ push(eax); |
2105 | 842 |
__ CallRuntime(RuntimeFunction(), 1); |
2106 | 843 |
} |
2107 |
__ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
|
844 |
__ movsd(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
|
|
2108 | 845 |
__ Ret(); |
2109 | 846 |
} |
2110 | 847 |
} |
... | ... | |
2221 | 958 |
} |
2222 | 959 |
|
2223 | 960 |
|
2224 |
// Input: edx, eax are the left and right objects of a bit op. |
|
2225 |
// Output: eax, ecx are left and right integers for a bit op. |
|
2226 |
// Warning: can clobber inputs even when it jumps to |conversion_failure|! |
|
2227 |
void FloatingPointHelper::LoadUnknownsAsIntegers( |
|
2228 |
MacroAssembler* masm, |
|
2229 |
bool use_sse3, |
|
2230 |
BinaryOpIC::TypeInfo left_type, |
|
2231 |
BinaryOpIC::TypeInfo right_type, |
|
2232 |
Label* conversion_failure) { |
|
2233 |
// Check float operands. |
|
2234 |
Label arg1_is_object, check_undefined_arg1; |
|
2235 |
Label arg2_is_object, check_undefined_arg2; |
|
2236 |
Label load_arg2, done; |
|
2237 |
|
|
2238 |
// Test if arg1 is a Smi. |
|
2239 |
if (left_type == BinaryOpIC::SMI) { |
|
2240 |
__ JumpIfNotSmi(edx, conversion_failure); |
|
2241 |
} else { |
|
2242 |
__ JumpIfNotSmi(edx, &arg1_is_object, Label::kNear); |
|
2243 |
} |
|
2244 |
|
|
2245 |
__ SmiUntag(edx); |
|
2246 |
__ jmp(&load_arg2); |
|
2247 |
|
|
2248 |
// If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
|
2249 |
__ bind(&check_undefined_arg1); |
|
2250 |
Factory* factory = masm->isolate()->factory(); |
|
2251 |
__ cmp(edx, factory->undefined_value()); |
|
2252 |
__ j(not_equal, conversion_failure); |
|
2253 |
__ mov(edx, Immediate(0)); |
|
2254 |
__ jmp(&load_arg2); |
Also available in: Unified diff