OLD | NEW |
---|---|
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 723 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
734 frame_->Push(&value); // Undo the Pop() from above. | 734 frame_->Push(&value); // Undo the Pop() from above. |
735 ToBooleanStub stub; | 735 ToBooleanStub stub; |
736 Result temp = frame_->CallStub(&stub, 1); | 736 Result temp = frame_->CallStub(&stub, 1); |
737 // Convert the result to a condition code. | 737 // Convert the result to a condition code. |
738 __ test(temp.reg(), Operand(temp.reg())); | 738 __ test(temp.reg(), Operand(temp.reg())); |
739 temp.Unuse(); | 739 temp.Unuse(); |
740 dest->Split(not_equal); | 740 dest->Split(not_equal); |
741 } | 741 } |
742 | 742 |
743 | 743 |
744 enum ArgsLocation { | |
745 ARGS_ON_STACK, | |
746 ARGS_IN_REGISTERS | |
747 }; | |
748 | |
749 | |
744 class FloatingPointHelper : public AllStatic { | 750 class FloatingPointHelper : public AllStatic { |
745 public: | 751 public: |
746 // Code pattern for loading a floating point value. Input value must | 752 // Code pattern for loading a floating point value. Input value must |
747 // be either a smi or a heap number object (fp value). Requirements: | 753 // be either a smi or a heap number object (fp value). Requirements: |
748 // operand in register number. Returns operand as floating point number | 754 // operand in register number. Returns operand as floating point number |
749 // on FPU stack. | 755 // on FPU stack. |
750 static void LoadFloatOperand(MacroAssembler* masm, Register number); | 756 static void LoadFloatOperand(MacroAssembler* masm, Register number); |
751 // Code pattern for loading floating point values. Input values must | 757 // Code pattern for loading floating point values. Input values must |
752 // be either smi or heap number objects (fp values). Requirements: | 758 // be either smi or heap number objects (fp values). Requirements: |
753 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as | 759 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax, |
754 // floating point numbers on FPU stack. | 760 // Returns operands as floating point numbers on FPU stack. |
755 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); | 761 static void LoadFloatOperands(MacroAssembler* masm, |
762 Register scratch, | |
763 ArgsLocation args_location = ARGS_ON_STACK); | |
764 | |
765 // Similar to LoadFloatOperand but assumes that both operands are smis. | |
766 // Accepts operands on stack or in eax,ebx. | |
Mads Ager (chromium)
2010/01/22 12:14:26
Space after comma.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
767 static void LoadFloatSmis(MacroAssembler* masm, | |
768 Register scratch, | |
769 ArgsLocation args_location); | |
770 | |
756 // Test if operands are smi or number objects (fp). Requirements: | 771 // Test if operands are smi or number objects (fp). Requirements: |
757 // operand_1 in eax, operand_2 in edx; falls through on float | 772 // operand_1 in eax, operand_2 in edx; falls through on float |
758 // operands, jumps to the non_float label otherwise. | 773 // operands, jumps to the non_float label otherwise. |
759 static void CheckFloatOperands(MacroAssembler* masm, | 774 static void CheckFloatOperands(MacroAssembler* masm, |
760 Label* non_float, | 775 Label* non_float, |
761 Register scratch); | 776 Register scratch); |
762 // Takes the operands in edx and eax and loads them as integers in eax | 777 // Takes the operands in edx and eax and loads them as integers in eax |
763 // and ecx. | 778 // and ecx. |
764 static void LoadAsIntegers(MacroAssembler* masm, | 779 static void LoadAsIntegers(MacroAssembler* masm, |
765 bool use_sse3, | 780 bool use_sse3, |
766 Label* operand_conversion_failure); | 781 Label* operand_conversion_failure); |
767 // Test if operands are numbers (smi or HeapNumber objects), and load | 782 // Test if operands are numbers (smi or HeapNumber objects), and load |
768 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | 783 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
769 // either operand is not a number. Operands are in edx and eax. | 784 // either operand is not a number. Operands are in edx and eax. |
770 // Leaves operands unchanged. | 785 // Leaves operands unchanged. |
771 static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers); | 786 static void LoadSse2Operands(MacroAssembler* masm, Label* not_numbers); |
787 | |
788 // Similar to LoadSse2Operands but assumes that both operands are smis. | |
789 // Accepts operands on stack or in eax,ebx. | |
Mads Ager (chromium)
2010/01/22 12:14:26
Space after comma.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
790 static void LoadSse2Smis(MacroAssembler* masm, | |
791 Register scratch, | |
792 ArgsLocation args_location); | |
772 }; | 793 }; |
773 | 794 |
774 | 795 |
796 const char* GenericBinaryOpStub::GetFastCaseName() { | |
797 switch (fast_case_) { | |
798 case BINARY_OP_STUB_UNINITIALIZED: return "Uninit"; | |
799 case BINARY_OP_STUB_GENERIC: return "Universal"; break; | |
Mads Ager (chromium)
2010/01/22 12:14:26
"Universal" -> "Generic"
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
800 case BINARY_OP_STUB_FAST_FP: return "FastFP"; break; | |
801 case BINARY_OP_STUB_FAST_STRING_ADD: return "FastStringAdd"; break; | |
802 case BINARY_OP_STUB_FAST_RUNTIME: return "FastRuntime"; break; | |
803 default: return "UnknownCase"; | |
804 } | |
805 } | |
806 | |
807 | |
775 const char* GenericBinaryOpStub::GetName() { | 808 const char* GenericBinaryOpStub::GetName() { |
776 if (name_ != NULL) return name_; | 809 if (name_ != NULL) return name_; |
777 const int kMaxNameLength = 100; | 810 const int kMaxNameLength = 100; |
778 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); | 811 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); |
779 if (name_ == NULL) return "OOM"; | 812 if (name_ == NULL) return "OOM"; |
813 char static_kind[kMaxNameLength]; | |
814 FormatStaticParameters(static_kind, kMaxNameLength); | |
815 OS::SNPrintF(Vector<char>(static_kind, kMaxNameLength), | |
816 "GenericBinaryOpStub_%s_%s", | |
817 static_kind, | |
818 GetFastCaseName()); | |
819 return name_; | |
820 } | |
821 | |
822 | |
823 void GenericBinaryOpStub::FormatStaticParameters(char* name, int max_length) { | |
780 const char* op_name = Token::Name(op_); | 824 const char* op_name = Token::Name(op_); |
781 const char* overwrite_name; | 825 const char* overwrite_name; |
782 switch (mode_) { | 826 switch (mode_) { |
783 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 827 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
784 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 828 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
785 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 829 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
786 default: overwrite_name = "UnknownOverwrite"; break; | 830 default: overwrite_name = "UnknownOverwrite"; break; |
787 } | 831 } |
788 | 832 OS::SNPrintF(Vector<char>(name, max_length), |
789 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 833 "%s_%s%s_%s%s", |
790 "GenericBinaryOpStub_%s_%s%s_%s%s", | |
791 op_name, | 834 op_name, |
792 overwrite_name, | 835 overwrite_name, |
793 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 836 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
794 args_in_registers_ ? "RegArgs" : "StackArgs", | 837 args_in_registers_ ? "RegArgs" : "StackArgs", |
795 args_reversed_ ? "_R" : ""); | 838 args_reversed_ ? "_R" : ""); |
796 return name_; | |
797 } | 839 } |
798 | 840 |
799 | 841 |
800 // Call the specialized stub for a binary operation. | 842 // Call the specialized stub for a binary operation. |
801 class DeferredInlineBinaryOperation: public DeferredCode { | 843 class DeferredInlineBinaryOperation: public DeferredCode { |
802 public: | 844 public: |
803 DeferredInlineBinaryOperation(Token::Value op, | 845 DeferredInlineBinaryOperation(Token::Value op, |
804 Register dst, | 846 Register dst, |
805 Register left, | 847 Register left, |
806 Register right, | 848 Register right, |
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1346 } else { | 1388 } else { |
1347 __ mov(answer.reg(), left->reg()); | 1389 __ mov(answer.reg(), left->reg()); |
1348 __ or_(answer.reg(), Operand(right->reg())); | 1390 __ or_(answer.reg(), Operand(right->reg())); |
1349 ASSERT(kSmiTag == 0); // Adjust test if not the case. | 1391 ASSERT(kSmiTag == 0); // Adjust test if not the case. |
1350 __ test(answer.reg(), Immediate(kSmiTagMask)); | 1392 __ test(answer.reg(), Immediate(kSmiTagMask)); |
1351 } | 1393 } |
1352 deferred->Branch(not_zero); | 1394 deferred->Branch(not_zero); |
1353 __ mov(answer.reg(), left->reg()); | 1395 __ mov(answer.reg(), left->reg()); |
1354 switch (op) { | 1396 switch (op) { |
1355 case Token::ADD: | 1397 case Token::ADD: |
1356 __ add(answer.reg(), Operand(right->reg())); // Add optimistically. | 1398 __ add(answer.reg(), Operand(right->reg())); |
1357 deferred->Branch(overflow); | 1399 deferred->Branch(overflow); |
1358 break; | 1400 break; |
1359 | 1401 |
1360 case Token::SUB: | 1402 case Token::SUB: |
1361 __ sub(answer.reg(), Operand(right->reg())); // Subtract optimistically. | 1403 __ sub(answer.reg(), Operand(right->reg())); |
1362 deferred->Branch(overflow); | 1404 deferred->Branch(overflow); |
1363 break; | 1405 break; |
1364 | 1406 |
1365 case Token::MUL: { | 1407 case Token::MUL: { |
1366 // If the smi tag is 0 we can just leave the tag on one operand. | 1408 // If the smi tag is 0 we can just leave the tag on one operand. |
1367 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | 1409 ASSERT(kSmiTag == 0); // Adjust code below if not the case. |
1368 // Remove smi tag from the left operand (but keep sign). | 1410 // Remove smi tag from the left operand (but keep sign). |
1369 // Left-hand operand has been copied into answer. | 1411 // Left-hand operand has been copied into answer. |
1370 __ SmiUntag(answer.reg()); | 1412 __ SmiUntag(answer.reg()); |
1371 // Do multiplication of smis, leaving result in answer. | 1413 // Do multiplication of smis, leaving result in answer. |
(...skipping 5684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7056 SetArgsInRegisters(); | 7098 SetArgsInRegisters(); |
7057 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 7099 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); |
7058 } | 7100 } |
7059 | 7101 |
7060 // Call the stub. | 7102 // Call the stub. |
7061 __ CallStub(this); | 7103 __ CallStub(this); |
7062 } | 7104 } |
7063 | 7105 |
7064 | 7106 |
7065 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { | 7107 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
7108 if (HasArgumentsInRegisters()) { | |
7109 __ mov(ebx, eax); | |
7110 __ mov(eax, edx); | |
7111 } else { | |
7112 __ mov(ebx, Operand(esp, 1 * kPointerSize)); | |
7113 __ mov(eax, Operand(esp, 2 * kPointerSize)); | |
7114 } | |
7115 | |
7116 Label not_smis, not_smis_or_overflow, use_fp_on_smis; | |
7117 | |
7066 // Perform fast-case smi code for the operation (eax <op> ebx) and | 7118 // Perform fast-case smi code for the operation (eax <op> ebx) and |
7067 // leave result in register eax. | 7119 // leave result in register eax. |
7068 | 7120 |
7069 // Prepare the smi check of both operands by or'ing them together | 7121 // Prepare the smi check of both operands by or'ing them together |
7070 // before checking against the smi mask. | 7122 // before checking against the smi mask. |
7071 __ mov(ecx, Operand(ebx)); | 7123 __ mov(ecx, Operand(ebx)); |
7072 __ or_(ecx, Operand(eax)); | 7124 __ or_(ecx, Operand(eax)); |
7073 | 7125 |
7074 switch (op_) { | 7126 switch (op_) { |
7075 case Token::ADD: | 7127 case Token::ADD: |
7076 __ add(eax, Operand(ebx)); // add optimistically | 7128 __ add(eax, Operand(ebx)); // add optimistically |
7077 __ j(overflow, slow, not_taken); | 7129 __ j(overflow, ¬_smis_or_overflow, not_taken); |
7078 break; | 7130 break; |
7079 | 7131 |
7080 case Token::SUB: | 7132 case Token::SUB: |
7081 __ sub(eax, Operand(ebx)); // subtract optimistically | 7133 __ sub(eax, Operand(ebx)); // subtract optimistically |
7082 __ j(overflow, slow, not_taken); | 7134 __ j(overflow, ¬_smis_or_overflow, not_taken); |
7083 break; | 7135 break; |
7084 | 7136 |
7085 case Token::DIV: | 7137 case Token::DIV: |
7086 case Token::MOD: | 7138 case Token::MOD: |
7087 // Sign extend eax into edx:eax. | 7139 // Sign extend eax into edx:eax. |
7088 __ cdq(); | 7140 __ cdq(); |
7089 // Check for 0 divisor. | 7141 // Check for 0 divisor. |
7090 __ test(ebx, Operand(ebx)); | 7142 __ test(ebx, Operand(ebx)); |
7091 __ j(zero, slow, not_taken); | 7143 __ j(zero, ¬_smis_or_overflow, not_taken); |
7092 break; | 7144 break; |
7093 | 7145 |
7094 default: | 7146 default: |
7095 // Fall-through to smi check. | 7147 // Fall-through to smi check. |
7096 break; | 7148 break; |
7097 } | 7149 } |
7098 | 7150 |
7099 // Perform the actual smi check. | 7151 // Perform the actual smi check. |
7100 ASSERT(kSmiTag == 0); // adjust zero check if not the case | 7152 ASSERT(kSmiTag == 0); // adjust zero check if not the case |
7101 __ test(ecx, Immediate(kSmiTagMask)); | 7153 __ test(ecx, Immediate(kSmiTagMask)); |
7102 __ j(not_zero, slow, not_taken); | 7154 __ j(not_zero, ¬_smis, not_taken); |
7103 | 7155 |
7104 switch (op_) { | 7156 switch (op_) { |
7105 case Token::ADD: | 7157 case Token::ADD: |
7106 case Token::SUB: | 7158 case Token::SUB: |
7107 // Do nothing here. | 7159 // Do nothing here. |
7108 break; | 7160 break; |
7109 | 7161 |
7110 case Token::MUL: | 7162 case Token::MUL: |
7111 // If the smi tag is 0 we can just leave the tag on one operand. | 7163 // If the smi tag is 0 we can just leave the tag on one operand. |
7112 ASSERT(kSmiTag == 0); // adjust code below if not the case | 7164 ASSERT(kSmiTag == 0); // adjust code below if not the case |
7113 // Remove tag from one of the operands (but keep sign). | 7165 // Remove tag from one of the operands (but keep sign). |
7114 __ SmiUntag(eax); | 7166 __ SmiUntag(eax); |
7115 // Do multiplication. | 7167 // Do multiplication. |
7116 __ imul(eax, Operand(ebx)); // multiplication of smis; result in eax | 7168 __ imul(eax, Operand(ebx)); // multiplication of smis; result in eax |
7117 // Go slow on overflows. | 7169 // Go slow on overflows. |
7118 __ j(overflow, slow, not_taken); | 7170 __ j(overflow, &use_fp_on_smis, not_taken); |
7119 // Check for negative zero result. | 7171 // Check for negative zero result. |
7120 __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y | 7172 __ NegativeZeroTest(eax, ecx, &use_fp_on_smis); // use ecx = x | y |
7121 break; | 7173 break; |
7122 | 7174 |
7123 case Token::DIV: | 7175 case Token::DIV: |
7124 // Divide edx:eax by ebx. | 7176 // Divide edx:eax by ebx. |
7125 __ idiv(ebx); | 7177 __ idiv(ebx); |
7126 // Check for the corner case of dividing the most negative smi | 7178 // Check for the corner case of dividing the most negative smi |
7127 // by -1. We cannot use the overflow flag, since it is not set | 7179 // by -1. We cannot use the overflow flag, since it is not set |
7128 // by idiv instruction. | 7180 // by idiv instruction. |
7129 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 7181 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
7130 __ cmp(eax, 0x40000000); | 7182 __ cmp(eax, 0x40000000); |
7131 __ j(equal, slow); | 7183 __ j(equal, &use_fp_on_smis); |
7132 // Check for negative zero result. | 7184 // Check for negative zero result. |
7133 __ NegativeZeroTest(eax, ecx, slow); // use ecx = x | y | 7185 __ NegativeZeroTest(eax, ecx, &use_fp_on_smis); // use ecx = x | y |
7134 // Check that the remainder is zero. | 7186 // Check that the remainder is zero. |
7135 __ test(edx, Operand(edx)); | 7187 __ test(edx, Operand(edx)); |
7136 __ j(not_zero, slow); | 7188 __ j(not_zero, &use_fp_on_smis); |
7137 // Tag the result and store it in register eax. | 7189 // Tag the result and store it in register eax. |
7138 __ SmiTag(eax); | 7190 __ SmiTag(eax); |
7139 break; | 7191 break; |
7140 | 7192 |
7141 case Token::MOD: | 7193 case Token::MOD: |
7142 // Divide edx:eax by ebx. | 7194 // Divide edx:eax by ebx. |
7143 __ idiv(ebx); | 7195 __ idiv(ebx); |
7144 // Check for negative zero result. | 7196 // Check for negative zero result. |
7145 __ NegativeZeroTest(edx, ecx, slow); // use ecx = x | y | 7197 __ NegativeZeroTest(edx, ecx, slow); // use ecx = x | y |
7146 // Move remainder to register eax. | 7198 // Move remainder to register eax. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7181 // - 0x40000000: this number would convert to negative when | 7233 // - 0x40000000: this number would convert to negative when |
7182 // Smi tagging these two cases can only happen with shifts | 7234 // Smi tagging these two cases can only happen with shifts |
7183 // by 0 or 1 when handed a valid smi. | 7235 // by 0 or 1 when handed a valid smi. |
7184 __ test(eax, Immediate(0xc0000000)); | 7236 __ test(eax, Immediate(0xc0000000)); |
7185 __ j(not_zero, slow, not_taken); | 7237 __ j(not_zero, slow, not_taken); |
7186 break; | 7238 break; |
7187 case Token::SHL: | 7239 case Token::SHL: |
7188 __ shl_cl(eax); | 7240 __ shl_cl(eax); |
7189 // Check that the *signed* result fits in a smi. | 7241 // Check that the *signed* result fits in a smi. |
7190 __ cmp(eax, 0xc0000000); | 7242 __ cmp(eax, 0xc0000000); |
7191 __ j(sign, slow, not_taken); | 7243 __ j(sign, &use_fp_on_smis, not_taken); |
7192 break; | 7244 break; |
7193 default: | 7245 default: |
7194 UNREACHABLE(); | 7246 UNREACHABLE(); |
7195 } | 7247 } |
7196 // Tag the result and store it in register eax. | 7248 // Tag the result and store it in register eax. |
7197 __ SmiTag(eax); | 7249 __ SmiTag(eax); |
7198 break; | 7250 break; |
7199 | 7251 |
7200 default: | 7252 default: |
7201 UNREACHABLE(); | 7253 UNREACHABLE(); |
7202 break; | 7254 break; |
7203 } | 7255 } |
7204 } | 7256 GenerateReturn(masm); |
7205 | 7257 |
7206 | 7258 __ bind(¬_smis_or_overflow); |
7207 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 7259 switch (op_) { |
7208 Label call_runtime; | 7260 case Token::ADD: __ sub(eax, Operand(ebx)); break; |
Mads Ager (chromium)
2010/01/22 12:14:26
Add comment that says that this reverts the optimi
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7209 | 7261 case Token::SUB: __ add(eax, Operand(ebx)); break; |
7210 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | 7262 default: break; |
7211 | |
7212 // Generate fast case smi code if requested. This flag is set when the fast | |
7213 // case smi code is not generated by the caller. Generating it here will speed | |
7214 // up common operations. | |
7215 if (HasSmiCodeInStub()) { | |
7216 Label slow; | |
7217 __ mov(ebx, Operand(esp, 1 * kPointerSize)); | |
7218 __ mov(eax, Operand(esp, 2 * kPointerSize)); | |
7219 GenerateSmiCode(masm, &slow); | |
7220 GenerateReturn(masm); | |
7221 // Too bad. The fast case smi code didn't succeed. | |
7222 __ bind(&slow); | |
7223 } | 7263 } |
7224 | 7264 |
7225 // Make sure the arguments are in edx and eax. | 7265 ASSERT(kSmiTag == 0); // adjust zero check if not the case |
7226 GenerateLoadArguments(masm); | 7266 __ test(ecx, Immediate(kSmiTagMask)); |
7267 __ j(not_zero, ¬_smis, not_taken); | |
7227 | 7268 |
7228 // Floating point case. | 7269 __ bind(&use_fp_on_smis); |
7270 Label after_alloc_failure; | |
7271 // Both operands are known to be SMIs but the result does not fit into a SMI. | |
7229 switch (op_) { | 7272 switch (op_) { |
7230 case Token::ADD: | 7273 case Token::ADD: |
7231 case Token::SUB: | 7274 case Token::SUB: |
7232 case Token::MUL: | 7275 case Token::MUL: |
7233 case Token::DIV: { | 7276 case Token::DIV: { |
7234 // eax: y | 7277 __ AllocateHeapNumber(edx, ecx, no_reg, |
Mads Ager (chromium)
2010/01/22 12:14:26
Reindent argument list:
__ AllocateHeapNumber(
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7235 // edx: x | 7278 HasArgumentsInRegisters() ? &after_alloc_failure : slow); |
7236 | |
7237 if (CpuFeatures::IsSupported(SSE2)) { | 7279 if (CpuFeatures::IsSupported(SSE2)) { |
7238 CpuFeatures::Scope use_sse2(SSE2); | 7280 CpuFeatures::Scope use_sse2(SSE2); |
7239 FloatingPointHelper::LoadSse2Operands(masm, &call_runtime); | 7281 FloatingPointHelper::LoadSse2Smis( |
7240 | 7282 masm, |
7283 ecx, | |
7284 HasArgumentsInRegisters() ? ARGS_IN_REGISTERS : ARGS_ON_STACK); | |
7241 switch (op_) { | 7285 switch (op_) { |
7242 case Token::ADD: __ addsd(xmm0, xmm1); break; | 7286 case Token::ADD: __ addsd(xmm0, xmm1); break; |
7243 case Token::SUB: __ subsd(xmm0, xmm1); break; | 7287 case Token::SUB: __ subsd(xmm0, xmm1); break; |
7244 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 7288 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
7245 case Token::DIV: __ divsd(xmm0, xmm1); break; | 7289 case Token::DIV: __ divsd(xmm0, xmm1); break; |
7246 default: UNREACHABLE(); | 7290 default: UNREACHABLE(); |
7247 } | 7291 } |
7248 // Allocate a heap number, if needed. | 7292 __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); |
7249 Label skip_allocation; | |
7250 switch (mode_) { | |
7251 case OVERWRITE_LEFT: | |
7252 __ mov(eax, Operand(edx)); | |
7253 // Fall through! | |
7254 case OVERWRITE_RIGHT: | |
7255 // If the argument in eax is already an object, we skip the | |
7256 // allocation of a heap number. | |
7257 __ test(eax, Immediate(kSmiTagMask)); | |
7258 __ j(not_zero, &skip_allocation, not_taken); | |
7259 // Fall through! | |
7260 case NO_OVERWRITE: { | |
7261 // Allocate a heap number for the result. Keep eax and edx intact | |
7262 // for the possible runtime call. | |
7263 __ AllocateHeapNumber(ebx, ecx, no_reg, &call_runtime); | |
7264 // Now eax can be overwritten losing one of the arguments as we are | |
7265 // now done and will not need it any more. | |
7266 __ mov(eax, ebx); | |
7267 __ bind(&skip_allocation); | |
7268 break; | |
7269 } | |
7270 default: UNREACHABLE(); | |
7271 } | |
7272 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | |
7273 GenerateReturn(masm); | |
7274 } else { // SSE2 not available, use FPU. | 7293 } else { // SSE2 not available, use FPU. |
7275 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 7294 FloatingPointHelper::LoadFloatSmis( |
7276 // Allocate a heap number, if needed. | 7295 masm, |
7277 Label skip_allocation; | 7296 ecx, |
7278 switch (mode_) { | 7297 HasArgumentsInRegisters() ? ARGS_IN_REGISTERS : ARGS_ON_STACK); |
7279 case OVERWRITE_LEFT: | |
7280 __ mov(eax, Operand(edx)); | |
7281 // Fall through! | |
7282 case OVERWRITE_RIGHT: | |
7283 // If the argument in eax is already an object, we skip the | |
7284 // allocation of a heap number. | |
7285 __ test(eax, Immediate(kSmiTagMask)); | |
7286 __ j(not_zero, &skip_allocation, not_taken); | |
7287 // Fall through! | |
7288 case NO_OVERWRITE: | |
7289 // Allocate a heap number for the result. Keep eax and edx intact | |
7290 // for the possible runtime call. | |
7291 __ AllocateHeapNumber(ebx, ecx, no_reg, &call_runtime); | |
7292 // Now eax can be overwritten losing one of the arguments as we are | |
7293 // now done and will not need it any more. | |
7294 __ mov(eax, ebx); | |
7295 __ bind(&skip_allocation); | |
7296 break; | |
7297 default: UNREACHABLE(); | |
7298 } | |
7299 FloatingPointHelper::LoadFloatOperands(masm, ecx); | |
7300 | |
7301 switch (op_) { | 7298 switch (op_) { |
7302 case Token::ADD: __ faddp(1); break; | 7299 case Token::ADD: __ faddp(1); break; |
7303 case Token::SUB: __ fsubp(1); break; | 7300 case Token::SUB: __ fsubp(1); break; |
7304 case Token::MUL: __ fmulp(1); break; | 7301 case Token::MUL: __ fmulp(1); break; |
7305 case Token::DIV: __ fdivp(1); break; | 7302 case Token::DIV: __ fdivp(1); break; |
7306 default: UNREACHABLE(); | 7303 default: UNREACHABLE(); |
7307 } | 7304 } |
7308 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 7305 __ fstp_d(FieldOperand(edx, HeapNumber::kValueOffset)); |
7309 GenerateReturn(masm); | 7306 } |
7310 } | 7307 __ mov(eax, edx); |
7311 } | 7308 GenerateReturn(masm); |
7312 case Token::MOD: { | |
7313 // For MOD we go directly to runtime in the non-smi case. | |
7314 break; | |
7315 } | 7309 } |
7316 case Token::BIT_OR: | 7310 case Token::BIT_OR: |
7317 case Token::BIT_AND: | 7311 case Token::BIT_AND: |
7318 case Token::BIT_XOR: | 7312 case Token::BIT_XOR: |
7319 case Token::SAR: | 7313 case Token::SAR: |
7320 case Token::SHL: | 7314 // These operations always succeed on a pair of smis. |
Mads Ager (chromium)
2010/01/22 12:14:26
That means that we should never get to this place,
vladislav.kaznacheev
2010/01/22 14:09:42
We never get to this place when executing, but we
| |
7321 case Token::SHR: { | 7315 break; |
7322 Label non_smi_result, skip_allocation; | 7316 |
7323 Label operand_conversion_failure; | 7317 case Token::MOD: |
7324 FloatingPointHelper::LoadAsIntegers( | 7318 case Token::SHR: |
7325 masm, | 7319 // These go directly to runtime |
Mads Ager (chromium)
2010/01/22 12:14:26
Similarly here: UNREACHABLE()?
Three-space indent
vladislav.kaznacheev
2010/01/22 14:09:42
See previous reply.
On 2010/01/22 12:14:26, Mads A
| |
7326 use_sse3_, | 7320 break; |
7327 &operand_conversion_failure); | 7321 |
7328 switch (op_) { | 7322 case Token::SHL: { |
7329 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | 7323 __ AllocateHeapNumber(ebx, ecx, edx, slow); |
7330 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | |
7331 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; | |
7332 case Token::SAR: __ sar_cl(eax); break; | |
7333 case Token::SHL: __ shl_cl(eax); break; | |
7334 case Token::SHR: __ shr_cl(eax); break; | |
7335 default: UNREACHABLE(); | |
7336 } | |
7337 if (op_ == Token::SHR) { | |
7338 // Check if result is non-negative and fits in a smi. | |
7339 __ test(eax, Immediate(0xc0000000)); | |
7340 __ j(not_zero, &non_smi_result); | |
7341 } else { | |
7342 // Check if result fits in a smi. | |
7343 __ cmp(eax, 0xc0000000); | |
7344 __ j(negative, &non_smi_result); | |
7345 } | |
7346 // Tag smi result and return. | |
7347 __ SmiTag(eax); | |
7348 GenerateReturn(masm); | |
7349 | |
7350 // All ops except SHR return a signed int32 that we load in a HeapNumber. | |
7351 if (op_ != Token::SHR) { | |
7352 __ bind(&non_smi_result); | |
7353 // Allocate a heap number if needed. | |
7354 __ mov(ebx, Operand(eax)); // ebx: result | |
7355 switch (mode_) { | |
7356 case OVERWRITE_LEFT: | |
7357 case OVERWRITE_RIGHT: | |
7358 // If the operand was an object, we skip the | |
7359 // allocation of a heap number. | |
7360 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | |
7361 1 * kPointerSize : 2 * kPointerSize)); | |
7362 __ test(eax, Immediate(kSmiTagMask)); | |
7363 __ j(not_zero, &skip_allocation, not_taken); | |
7364 // Fall through! | |
7365 case NO_OVERWRITE: | |
7366 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | |
7367 __ bind(&skip_allocation); | |
7368 break; | |
7369 default: UNREACHABLE(); | |
7370 } | |
7371 // Store the result in the HeapNumber and return. | 7324 // Store the result in the HeapNumber and return. |
7372 if (CpuFeatures::IsSupported(SSE2)) { | 7325 if (CpuFeatures::IsSupported(SSE2)) { |
7373 CpuFeatures::Scope use_sse2(SSE2); | 7326 CpuFeatures::Scope use_sse2(SSE2); |
7374 __ cvtsi2sd(xmm0, Operand(ebx)); | 7327 __ cvtsi2sd(xmm0, Operand(eax)); |
7328 __ movdbl(FieldOperand(ebx, HeapNumber::kValueOffset), xmm0); | |
7329 } else { | |
7330 __ mov(Operand(esp, 1 * kPointerSize), eax); | |
7331 __ fild_s(Operand(esp, 1 * kPointerSize)); | |
7332 __ fstp_d(FieldOperand(ebx, HeapNumber::kValueOffset)); | |
7333 } | |
7334 __ mov(eax, ebx); | |
7335 GenerateReturn(masm); | |
7336 break; | |
7337 } | |
7338 | |
7339 default: UNREACHABLE(); break; | |
Mads Ager (chromium)
2010/01/22 12:14:26
Indentation is off for the cases in this switch.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7340 } | |
7341 | |
7342 if (HasArgumentsInRegisters()) { | |
7343 __ bind(&after_alloc_failure); | |
7344 __ mov(edx, eax); | |
7345 __ mov(eax, ebx); | |
7346 __ jmp(slow); | |
7347 } | |
7348 | |
7349 __ bind(¬_smis); | |
7350 | |
7351 if (HasArgumentsInRegisters()) { | |
7352 __ mov(edx, eax); | |
7353 __ mov(eax, ebx); | |
7354 } | |
7355 } | |
7356 | |
7357 | |
7358 | |
7359 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | |
7360 Label call_runtime; | |
7361 | |
7362 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | |
7363 | |
7364 // Generate fast case smi code if requested. This flag is set when the fast | |
7365 // case smi code is not generated by the caller. Generating it here will speed | |
7366 // up common operations. | |
7367 | |
7368 if (ShouldGenerateSmiCode()) { | |
7369 GenerateSmiCode(masm, &call_runtime); | |
7370 } | |
7371 | |
7372 // Floating point case. | |
7373 if (ShouldGenerateFPCode()) { | |
7374 Label not_floats; | |
7375 | |
7376 switch (op_) { | |
7377 case Token::ADD: | |
7378 case Token::SUB: | |
7379 case Token::MUL: | |
7380 case Token::DIV: { | |
7381 // Make sure the arguments are in edx and eax. | |
7382 GenerateLoadArguments(masm); | |
7383 // eax: y | |
7384 // edx: x | |
7385 if (CpuFeatures::IsSupported(SSE2)) { | |
7386 CpuFeatures::Scope use_sse2(SSE2); | |
7387 FloatingPointHelper::LoadSse2Operands(masm, ¬_floats); | |
7388 | |
7389 switch (op_) { | |
7390 case Token::ADD: __ addsd(xmm0, xmm1); break; | |
7391 case Token::SUB: __ subsd(xmm0, xmm1); break; | |
7392 case Token::MUL: __ mulsd(xmm0, xmm1); break; | |
7393 case Token::DIV: __ divsd(xmm0, xmm1); break; | |
7394 default: UNREACHABLE(); | |
7395 } | |
7396 GenerateHeapResultAllocation(masm, &call_runtime); | |
7375 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 7397 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
7398 GenerateSwitchAndReturn(masm, BINARY_OP_STUB_FAST_FP); | |
7399 } else { // SSE2 not available, use FPU. | |
7400 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); | |
7401 FloatingPointHelper::LoadFloatOperands(masm, ecx, ARGS_ON_STACK); | |
7402 switch (op_) { | |
7403 case Token::ADD: __ faddp(1); break; | |
7404 case Token::SUB: __ fsubp(1); break; | |
7405 case Token::MUL: __ fmulp(1); break; | |
7406 case Token::DIV: __ fdivp(1); break; | |
7407 default: UNREACHABLE(); | |
7408 } | |
7409 Label after_alloc_failure; | |
7410 GenerateHeapResultAllocation(masm, &after_alloc_failure); | |
7411 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
7412 GenerateSwitchAndReturn(masm, BINARY_OP_STUB_FAST_FP); | |
7413 __ bind(&after_alloc_failure); | |
7414 __ fstp(0); | |
7415 __ jmp(&call_runtime); | |
7416 } | |
7417 } | |
7418 case Token::MOD: { | |
7419 // For MOD we go directly to runtime in the non-smi case. | |
Mads Ager (chromium)
2010/01/22 12:14:26
UNREACHABLE()?
vladislav.kaznacheev
2010/01/22 14:09:42
Similarly, this line is executed on code generatio
| |
7420 break; | |
7421 } | |
7422 case Token::BIT_OR: | |
7423 case Token::BIT_AND: | |
7424 case Token::BIT_XOR: | |
7425 case Token::SAR: | |
7426 case Token::SHL: | |
7427 case Token::SHR: { | |
7428 GenerateLoadArguments(masm); | |
7429 Label non_smi_result, skip_allocation; | |
7430 FloatingPointHelper::LoadAsIntegers( | |
7431 masm, | |
7432 use_sse3_, | |
7433 &call_runtime); | |
7434 switch (op_) { | |
7435 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | |
7436 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | |
7437 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; | |
7438 case Token::SAR: __ sar_cl(eax); break; | |
7439 case Token::SHL: __ shl_cl(eax); break; | |
7440 case Token::SHR: __ shr_cl(eax); break; | |
7441 default: UNREACHABLE(); | |
7442 } | |
7443 if (op_ == Token::SHR) { | |
7444 // Check if result is non-negative and fits in a smi. | |
7445 __ test(eax, Immediate(0xc0000000)); | |
7446 __ j(not_zero, &call_runtime); | |
7376 } else { | 7447 } else { |
7377 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 7448 // Check if result fits in a smi. |
7378 __ fild_s(Operand(esp, 1 * kPointerSize)); | 7449 __ cmp(eax, 0xc0000000); |
7379 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 7450 __ j(negative, &non_smi_result); |
7380 } | 7451 } |
7452 // Tag smi result and return. | |
7453 __ SmiTag(eax); | |
7381 GenerateReturn(masm); | 7454 GenerateReturn(masm); |
7382 } | 7455 |
7383 | 7456 // All ops except SHR return a signed int32 that we load in |
7384 // Go to runtime for non-number inputs. | 7457 // a HeapNumber. |
7385 __ bind(&operand_conversion_failure); | 7458 if (op_ != Token::SHR) { |
7386 // SHR should return uint32 - go to runtime for non-smi/negative result. | 7459 __ bind(&non_smi_result); |
7387 if (op_ == Token::SHR) { | 7460 // Allocate a heap number if needed. |
7388 __ bind(&non_smi_result); | 7461 __ mov(ebx, Operand(eax)); // ebx: result |
7389 } | 7462 switch (mode_) { |
7390 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 7463 case OVERWRITE_LEFT: |
7391 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 7464 case OVERWRITE_RIGHT: |
7392 break; | 7465 // If the operand was an object, we skip the |
7393 } | 7466 // allocation of a heap number. |
7394 default: UNREACHABLE(); break; | 7467 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
7395 } | 7468 1 * kPointerSize : 2 * kPointerSize)); |
7396 | 7469 __ test(eax, Immediate(kSmiTagMask)); |
7397 // If all else fails, use the runtime system to get the correct | 7470 __ j(not_zero, &skip_allocation, not_taken); |
7398 // result. If arguments was passed in registers now place them on the | 7471 // Fall through! |
7399 // stack in the correct order below the return address. | 7472 case NO_OVERWRITE: |
7400 __ bind(&call_runtime); | 7473 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
7474 __ bind(&skip_allocation); | |
7475 break; | |
7476 default: UNREACHABLE(); | |
7477 } | |
7478 // Store the result in the HeapNumber and return. | |
7479 if (CpuFeatures::IsSupported(SSE2)) { | |
7480 CpuFeatures::Scope use_sse2(SSE2); | |
7481 __ cvtsi2sd(xmm0, Operand(ebx)); | |
7482 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | |
7483 } else { | |
7484 __ mov(Operand(esp, 1 * kPointerSize), ebx); | |
7485 __ fild_s(Operand(esp, 1 * kPointerSize)); | |
7486 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
7487 } | |
7488 GenerateReturn(masm); | |
7489 } | |
7490 | |
7491 break; | |
7492 } | |
7493 default: UNREACHABLE(); break; | |
7494 } | |
7495 __ bind(¬_floats); | |
7496 } | |
7497 | |
7498 switch (op_) { | |
7499 case Token::ADD: { | |
7500 if (ShouldGenerateStringAddCode()) { | |
7501 // Test for string arguments before calling runtime. | |
7502 Label not_strings, not_string1, string1; | |
7503 Result answer; | |
7504 | |
7505 // If this stub generated FP-specific code then the arguments | |
7506 // are already in edx,eax | |
Mads Ager (chromium)
2010/01/22 12:14:26
Space after comma.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7507 if (!ShouldGenerateFPCode()) { | |
7508 GenerateLoadArguments(masm); | |
7509 } | |
7510 | |
7511 __ test(edx, Immediate(kSmiTagMask)); | |
7512 __ j(zero, ¬_string1); | |
7513 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx); | |
7514 __ j(above_equal, ¬_string1); | |
7515 | |
7516 // First argument is a a string, test second. | |
Mads Ager (chromium)
2010/01/22 12:14:26
a a -> a
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7517 __ test(eax, Immediate(kSmiTagMask)); | |
7518 __ j(zero, &string1); | |
7519 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | |
7520 __ j(above_equal, &string1); | |
7521 | |
7522 // First and second argument are strings. Use the string add stub. | |
7523 StringAddStub stub(NO_STRING_CHECK_IN_STUB); | |
7524 GenerateSwitchViaStub(masm, stub, BINARY_OP_STUB_FAST_STRING_ADD); | |
7525 | |
7526 // Only first argument is a string. | |
7527 __ bind(&string1); | |
7528 GenerateSwitchViaBuiltin( | |
7529 masm, | |
7530 HasArgumentsReversed() ? | |
7531 Builtins::STRING_ADD_RIGHT : | |
7532 Builtins::STRING_ADD_LEFT, | |
7533 NULL, | |
7534 BINARY_OP_STUB_FAST_STRING_ADD); | |
7535 | |
7536 // First argument was not a string, test second. | |
7537 __ bind(¬_string1); | |
7538 __ test(eax, Immediate(kSmiTagMask)); | |
7539 __ j(zero, ¬_strings); | |
7540 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | |
7541 __ j(above_equal, ¬_strings); | |
7542 | |
7543 // Only second argument is a string. | |
7544 GenerateSwitchViaBuiltin( | |
7545 masm, | |
7546 HasArgumentsReversed() ? | |
7547 Builtins::STRING_ADD_LEFT : | |
7548 Builtins::STRING_ADD_RIGHT, | |
7549 NULL, | |
7550 BINARY_OP_STUB_FAST_STRING_ADD); | |
7551 | |
7552 __ bind(¬_strings); | |
7553 } | |
7554 GenerateSwitchViaBuiltin( | |
7555 masm, | |
7556 Builtins::ADD, | |
7557 &call_runtime, | |
7558 BINARY_OP_STUB_FAST_RUNTIME); | |
7559 break; | |
7560 } | |
7561 case Token::SUB: | |
7562 GenerateSwitchViaBuiltin( | |
7563 masm, | |
7564 Builtins::SUB, | |
7565 &call_runtime, | |
7566 BINARY_OP_STUB_FAST_RUNTIME); | |
7567 break; | |
7568 case Token::MUL: | |
7569 GenerateBuiltinTailCall(masm, Builtins::MUL, &call_runtime); | |
7570 break; | |
Mads Ager (chromium)
2010/01/22 12:14:26
indentation.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7571 case Token::DIV: | |
7572 GenerateBuiltinTailCall(masm, Builtins::DIV, &call_runtime); | |
7573 break; | |
7574 case Token::MOD: | |
7575 GenerateBuiltinTailCall(masm, Builtins::MOD, &call_runtime); | |
7576 break; | |
7577 case Token::BIT_OR: | |
7578 GenerateBuiltinTailCall(masm, Builtins::BIT_OR, &call_runtime); | |
7579 break; | |
7580 case Token::BIT_AND: | |
7581 GenerateBuiltinTailCall(masm, Builtins::BIT_AND, &call_runtime); | |
7582 break; | |
7583 case Token::BIT_XOR: | |
7584 GenerateBuiltinTailCall(masm, Builtins::BIT_XOR, &call_runtime); | |
7585 break; | |
7586 case Token::SAR: | |
7587 GenerateBuiltinTailCall(masm, Builtins::SAR, &call_runtime); | |
7588 break; | |
7589 case Token::SHL: | |
7590 GenerateBuiltinTailCall(masm, Builtins::SHL, &call_runtime); | |
7591 break; | |
7592 case Token::SHR: | |
7593 GenerateBuiltinTailCall(masm, Builtins::SHR, &call_runtime); | |
7594 break; | |
7595 default: | |
7596 UNREACHABLE(); | |
7597 } | |
7598 | |
7599 // Generate the unreachable reference to the original stub so that it can be | |
Mads Ager (chromium)
2010/01/22 12:14:26
the -> an
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7600 // found at the end of this stub when clearing ICs at GC. | |
7601 if (fast_case_ != BINARY_OP_STUB_UNINITIALIZED) { | |
7602 int key = TransitionMinorKey(MinorKey(), BINARY_OP_STUB_UNINITIALIZED); | |
7603 GenericBinaryOpStub uninit(key); | |
7604 __ TailCallStub(&uninit); | |
7605 } | |
7606 } | |
7607 | |
7608 | |
7609 int GenericBinaryOpStub::GetICState() { | |
7610 switch (fast_case_) { | |
7611 case BINARY_OP_STUB_UNINITIALIZED: return UNINITIALIZED; | |
7612 case BINARY_OP_STUB_GENERIC: return MEGAMORPHIC; | |
7613 default: return MONOMORPHIC; | |
7614 } | |
7615 } | |
7616 | |
7617 | |
7618 BinaryFastCase GenericBinaryOpStub::GetFastCase(BinaryFastCase target_case) { | |
7619 if (fast_case_ == target_case || fast_case_ == BINARY_OP_STUB_GENERIC) | |
7620 return fast_case_; | |
7621 | |
7622 switch (target_case) { | |
7623 case BINARY_OP_STUB_FAST_FP: | |
7624 if (ShouldGenerateSmiCode() && | |
7625 (fast_case_ == BINARY_OP_STUB_UNINITIALIZED)) { | |
Mads Ager (chromium)
2010/01/22 12:14:26
Indent one more space.
Could you add a comment ex
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7626 return BINARY_OP_STUB_FAST_FP; | |
7627 } | |
7628 break; | |
7629 | |
7630 case BINARY_OP_STUB_FAST_STRING_ADD: | |
7631 if (fast_case_ == BINARY_OP_STUB_UNINITIALIZED) | |
7632 return BINARY_OP_STUB_FAST_STRING_ADD; | |
7633 break; | |
7634 | |
7635 case BINARY_OP_STUB_FAST_RUNTIME: | |
7636 if (fast_case_ == BINARY_OP_STUB_UNINITIALIZED) | |
7637 return BINARY_OP_STUB_FAST_RUNTIME; | |
7638 break; | |
7639 | |
7640 case BINARY_OP_STUB_GENERIC: | |
7641 break; | |
7642 | |
7643 default: UNREACHABLE(); | |
7644 } | |
7645 | |
7646 return BINARY_OP_STUB_GENERIC; | |
7647 } | |
7648 | |
7649 | |
7650 void GenericBinaryOpStub::GenerateFastCaseSwitch(MacroAssembler* masm, | |
7651 BinaryFastCase fast_case) { | |
7652 int argc = 2; | |
7653 __ pop(ecx); | |
7654 __ push(eax); | |
Mads Ager (chromium)
2010/01/22 12:14:26
Add comment explaining what eax is here to make th
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7655 __ push(Immediate(Smi::FromInt(TransitionMinorKey(MinorKey(), fast_case)))); | |
7656 // __ push(eax); | |
Mads Ager (chromium)
2010/01/22 12:14:26
Code in comment.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7657 #ifdef DEBUG | |
7658 __ push(Immediate(Smi::FromInt(TransitionMinorKey(MinorKey(), fast_case_)))); | |
7659 argc++; | |
7660 #endif | |
7661 __ push(ecx); | |
7662 __ TailCallRuntime(ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), | |
7663 argc, | |
7664 1); | |
7665 } | |
7666 | |
7667 | |
7668 void GenericBinaryOpStub::GenerateBuiltinCallPrologue(MacroAssembler* masm) { | |
7669 if (HasArgumentsInRegisters()) { | |
7670 __ EnterInternalFrame(); | |
7671 if (HasArgumentsReversed()) { | |
7672 __ push(eax); | |
7673 __ push(edx); | |
7674 } else { | |
7675 __ push(edx); | |
7676 __ push(eax); | |
7677 } | |
7678 } else { | |
7679 __ pop(ecx); | |
7680 __ pop(eax); | |
Mads Ager (chromium)
2010/01/22 12:14:26
Popping the arguments instead of loading them seem
vladislav.kaznacheev
2010/01/22 14:09:42
There is always a tail call following this so we n
| |
7681 __ pop(edx); | |
7682 __ push(ecx); | |
7683 __ EnterInternalFrame(); | |
7684 __ push(edx); | |
7685 __ push(eax); | |
7686 } | |
7687 } | |
7688 | |
7689 void GenericBinaryOpStub::GenerateBuiltinCallEpilogue(MacroAssembler* masm) { | |
7690 __ LeaveInternalFrame(); | |
7691 } | |
7692 | |
7693 | |
7694 void GenericBinaryOpStub::GenerateBuiltinTailCall( | |
7695 MacroAssembler* masm, | |
7696 Builtins::JavaScript id, | |
7697 Label* exit_via_builtin) { | |
7698 if (exit_via_builtin) { | |
7699 __ bind(exit_via_builtin); | |
7700 } | |
7701 GenerateRegisterArgumentsPush(masm); | |
7702 __ InvokeBuiltin(id, JUMP_FUNCTION); | |
7703 } | |
7704 | |
7705 | |
7706 void GenericBinaryOpStub::GenerateSwitchAndReturn( | |
7707 MacroAssembler* masm, | |
7708 BinaryFastCase target_fast_case) { | |
7709 BinaryFastCase new_fast_case = GetFastCase(target_fast_case); | |
7710 if (new_fast_case != fast_case_) { | |
7711 if (!HasArgumentsInRegisters()) { | |
7712 __ pop(ecx); // return address | |
7713 __ pop(ebx); // drop second arg | |
7714 __ pop(edx); // drop first arg | |
7715 __ push(ecx); | |
7716 } | |
7717 GenerateFastCaseSwitch(masm, new_fast_case); | |
7718 } else { | |
7719 GenerateReturn(masm); | |
7720 } | |
7721 } | |
7722 | |
7723 | |
7724 void GenericBinaryOpStub::GenerateSwitchViaBuiltin( | |
7725 MacroAssembler* masm, | |
7726 Builtins::JavaScript id, | |
7727 Label* exit_via_builtin, | |
7728 BinaryFastCase target_fast_case) { | |
7729 BinaryFastCase new_fast_case = GetFastCase(target_fast_case); | |
7730 if (new_fast_case != fast_case_) { | |
7731 GenerateBuiltinCallPrologue(masm); | |
7732 __ InvokeBuiltin(id, CALL_FUNCTION); | |
7733 GenerateBuiltinCallEpilogue(masm); | |
7734 GenerateFastCaseSwitch(masm, new_fast_case); | |
7735 if (exit_via_builtin) { | |
7736 GenerateBuiltinTailCall(masm, id, exit_via_builtin); | |
7737 } | |
7738 } else { | |
7739 GenerateBuiltinTailCall(masm, id, exit_via_builtin); | |
7740 } | |
7741 } | |
7742 | |
7743 | |
7744 void GenericBinaryOpStub::GenerateSwitchViaStub( | |
7745 MacroAssembler* masm, | |
7746 CodeStub& stub, | |
7747 BinaryFastCase target_fast_case) { | |
7748 BinaryFastCase new_fast_case = GetFastCase(target_fast_case); | |
7749 if (new_fast_case != fast_case_) { | |
7750 GenerateBuiltinCallPrologue(masm); | |
7751 __ CallStub(&stub); | |
7752 GenerateBuiltinCallEpilogue(masm); | |
7753 GenerateFastCaseSwitch(masm, new_fast_case); | |
7754 } else { | |
7755 GenerateRegisterArgumentsPush(masm); | |
7756 __ TailCallStub(&stub); | |
7757 } | |
7758 } | |
7759 | |
7760 | |
7761 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, | |
7762 Label* alloc_failure) { | |
Mads Ager (chromium)
2010/01/22 12:14:26
Indentation.
vladislav.kaznacheev
2010/01/22 14:09:42
Done.
| |
7763 Label skip_allocation; | |
7764 OverwriteMode mode = mode_; | |
7765 if (HasArgumentsReversed()) { | |
7766 if (mode == OVERWRITE_RIGHT) | |
7767 mode = OVERWRITE_LEFT; | |
7768 else if (mode == OVERWRITE_LEFT) | |
7769 mode = OVERWRITE_RIGHT; | |
7770 } | |
7771 switch (mode) { | |
7772 case OVERWRITE_LEFT: { | |
7773 // If the argument in edx is already an object, we skip the | |
7774 // allocation of a heap number. | |
7775 __ test(edx, Immediate(kSmiTagMask)); | |
7776 __ j(not_zero, &skip_allocation, not_taken); | |
7777 // Allocate a heap number for the result. Keep eax and edx intact | |
7778 // for the possible runtime call. | |
7779 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); | |
7780 // Now edx can be overwritten losing one of the arguments as we are | |
7781 // now done and will not need it any more. | |
7782 __ mov(edx, Operand(ebx)); | |
7783 __ bind(&skip_allocation); | |
7784 // Use object in edx as a result holder | |
7785 __ mov(eax, Operand(edx)); | |
7786 break; | |
7787 } | |
7788 case OVERWRITE_RIGHT: | |
7789 // If the argument in eax is already an object, we skip the | |
7790 // allocation of a heap number. | |
7791 __ test(eax, Immediate(kSmiTagMask)); | |
7792 __ j(not_zero, &skip_allocation, not_taken); | |
7793 // Fall through! | |
7794 case NO_OVERWRITE: | |
7795 // Allocate a heap number for the result. Keep eax and edx intact | |
7796 // for the possible runtime call. | |
7797 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); | |
7798 // Now eax can be overwritten losing one of the arguments as we are | |
7799 // now done and will not need it any more. | |
7800 __ mov(eax, ebx); | |
7801 __ bind(&skip_allocation); | |
7802 break; | |
7803 default: UNREACHABLE(); | |
7804 } | |
7805 } | |
7806 | |
7807 | |
7808 void GenericBinaryOpStub::GenerateRegisterArgumentsPush(MacroAssembler* masm) { | |
7809 // Builtin functions expect arguments on stack so we need to push them | |
7810 // there in the correct order. | |
7401 if (HasArgumentsInRegisters()) { | 7811 if (HasArgumentsInRegisters()) { |
7402 __ pop(ecx); | 7812 __ pop(ecx); |
7403 if (HasArgumentsReversed()) { | 7813 if (HasArgumentsReversed()) { |
7404 __ push(eax); | 7814 __ push(eax); |
7405 __ push(edx); | 7815 __ push(edx); |
7406 } else { | 7816 } else { |
7407 __ push(edx); | 7817 __ push(edx); |
7408 __ push(eax); | 7818 __ push(eax); |
7409 } | 7819 } |
7410 __ push(ecx); | 7820 __ push(ecx); |
7411 } | 7821 } |
7412 switch (op_) { | |
7413 case Token::ADD: { | |
7414 // Test for string arguments before calling runtime. | |
7415 Label not_strings, not_string1, string1; | |
7416 Result answer; | |
7417 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | |
7418 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | |
7419 __ test(eax, Immediate(kSmiTagMask)); | |
7420 __ j(zero, ¬_string1); | |
7421 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, eax); | |
7422 __ j(above_equal, ¬_string1); | |
7423 | |
7424 // First argument is a a string, test second. | |
7425 __ test(edx, Immediate(kSmiTagMask)); | |
7426 __ j(zero, &string1); | |
7427 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx); | |
7428 __ j(above_equal, &string1); | |
7429 | |
7430 // First and second argument are strings. Jump to the string add stub. | |
7431 StringAddStub stub(NO_STRING_CHECK_IN_STUB); | |
7432 __ TailCallStub(&stub); | |
7433 | |
7434 // Only first argument is a string. | |
7435 __ bind(&string1); | |
7436 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); | |
7437 | |
7438 // First argument was not a string, test second. | |
7439 __ bind(¬_string1); | |
7440 __ test(edx, Immediate(kSmiTagMask)); | |
7441 __ j(zero, ¬_strings); | |
7442 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx); | |
7443 __ j(above_equal, ¬_strings); | |
7444 | |
7445 // Only second argument is a string. | |
7446 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); | |
7447 | |
7448 __ bind(¬_strings); | |
7449 // Neither argument is a string. | |
7450 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | |
7451 break; | |
7452 } | |
7453 case Token::SUB: | |
7454 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | |
7455 break; | |
7456 case Token::MUL: | |
7457 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); | |
7458 break; | |
7459 case Token::DIV: | |
7460 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); | |
7461 break; | |
7462 case Token::MOD: | |
7463 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); | |
7464 break; | |
7465 case Token::BIT_OR: | |
7466 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); | |
7467 break; | |
7468 case Token::BIT_AND: | |
7469 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); | |
7470 break; | |
7471 case Token::BIT_XOR: | |
7472 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); | |
7473 break; | |
7474 case Token::SAR: | |
7475 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); | |
7476 break; | |
7477 case Token::SHL: | |
7478 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | |
7479 break; | |
7480 case Token::SHR: | |
7481 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | |
7482 break; | |
7483 default: | |
7484 UNREACHABLE(); | |
7485 } | |
7486 } | 7822 } |
7487 | 7823 |
7488 | 7824 |
7489 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { | 7825 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
7490 // If arguments are not passed in registers read them from the stack. | 7826 // If arguments are not passed in registers read them from the stack. |
7491 if (!HasArgumentsInRegisters()) { | 7827 if (!HasArgumentsInRegisters()) { |
7492 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 7828 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
7493 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 7829 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
7494 } | 7830 } |
7495 } | 7831 } |
7496 | 7832 |
7497 | 7833 |
7498 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { | 7834 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { |
7499 // If arguments are not passed in registers remove them from the stack before | 7835 // If arguments are not passed in registers remove them from the stack before |
7500 // returning. | 7836 // returning. |
7501 if (!HasArgumentsInRegisters()) { | 7837 if (!HasArgumentsInRegisters()) { |
7502 __ ret(2 * kPointerSize); // Remove both operands | 7838 __ ret(2 * kPointerSize); // Remove both operands |
7503 } else { | 7839 } else { |
7504 __ ret(0); | 7840 __ ret(0); |
7505 } | 7841 } |
7506 } | 7842 } |
7507 | 7843 |
7508 | 7844 |
7845 Code* GetBinaryOpStub(int minor_key) { | |
7846 HandleScope scope; | |
7847 GenericBinaryOpStub stub(minor_key); | |
7848 return *stub.GetCode(); | |
7849 } | |
7850 | |
7851 | |
7852 #ifdef DEBUG | |
7853 void TraceBinaryOp(int old_key, int new_key) { | |
7854 GenericBinaryOpStub old_stub(old_key); | |
7855 GenericBinaryOpStub new_stub(new_key); | |
7856 const int kMaxNameLength = 100; | |
7857 char old_name[kMaxNameLength]; | |
7858 old_stub.FormatStaticParameters(old_name, kMaxNameLength); | |
7859 PrintF("[BinaryOpIC (%s->%s)#%s]\n", | |
7860 old_stub.GetFastCaseName(), | |
7861 new_stub.GetFastCaseName(), | |
7862 old_name); | |
7863 } | |
7864 #endif // DEBUG | |
7865 | |
7866 | |
7509 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 7867 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
7510 // is faster than using the built-in instructions on floating point registers. | 7868 // is faster than using the built-in instructions on floating point registers. |
7511 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 7869 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
7512 // trashed registers. | 7870 // trashed registers. |
7513 void IntegerConvert(MacroAssembler* masm, | 7871 void IntegerConvert(MacroAssembler* masm, |
7514 Register source, | 7872 Register source, |
7515 bool use_sse3, | 7873 bool use_sse3, |
7516 Label* conversion_failure) { | 7874 Label* conversion_failure) { |
7517 Label done, right_exponent, normal_exponent; | 7875 Label done, right_exponent, normal_exponent; |
7518 Register scratch = ebx; | 7876 Register scratch = ebx; |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7741 __ SmiUntag(eax); // Untag smi before converting to float. | 8099 __ SmiUntag(eax); // Untag smi before converting to float. |
7742 __ cvtsi2sd(xmm1, Operand(eax)); | 8100 __ cvtsi2sd(xmm1, Operand(eax)); |
7743 __ SmiTag(eax); // Retag smi for heap number overwriting test. | 8101 __ SmiTag(eax); // Retag smi for heap number overwriting test. |
7744 __ jmp(&done); | 8102 __ jmp(&done); |
7745 __ bind(&load_float_eax); | 8103 __ bind(&load_float_eax); |
7746 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 8104 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
7747 __ bind(&done); | 8105 __ bind(&done); |
7748 } | 8106 } |
7749 | 8107 |
7750 | 8108 |
8109 void FloatingPointHelper::LoadSse2Smis(MacroAssembler* masm, | |
8110 Register scratch, | |
8111 ArgsLocation args_location) { | |
8112 if (args_location == ARGS_IN_REGISTERS) { | |
8113 __ mov(scratch, eax); | |
8114 } else { | |
8115 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | |
8116 } | |
8117 __ SmiUntag(scratch); // Untag smi before converting to float. | |
8118 __ cvtsi2sd(xmm0, Operand(scratch)); | |
8119 | |
8120 | |
8121 if (args_location == ARGS_IN_REGISTERS) { | |
8122 __ mov(scratch, ebx); | |
8123 } else { | |
8124 __ mov(scratch, Operand(esp, 1 * kPointerSize)); | |
8125 } | |
8126 __ SmiUntag(scratch); // Untag smi before converting to float. | |
8127 __ cvtsi2sd(xmm1, Operand(scratch)); | |
8128 } | |
8129 | |
8130 | |
7751 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, | 8131 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, |
7752 Register scratch) { | 8132 Register scratch, |
8133 ArgsLocation args_location) { | |
7753 Label load_smi_1, load_smi_2, done_load_1, done; | 8134 Label load_smi_1, load_smi_2, done_load_1, done; |
7754 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | 8135 if (args_location == ARGS_IN_REGISTERS) { |
8136 __ mov(scratch, edx); | |
8137 } else { | |
8138 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | |
8139 } | |
7755 __ test(scratch, Immediate(kSmiTagMask)); | 8140 __ test(scratch, Immediate(kSmiTagMask)); |
7756 __ j(zero, &load_smi_1, not_taken); | 8141 __ j(zero, &load_smi_1, not_taken); |
7757 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); | 8142 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
7758 __ bind(&done_load_1); | 8143 __ bind(&done_load_1); |
7759 | 8144 |
7760 __ mov(scratch, Operand(esp, 1 * kPointerSize)); | 8145 if (args_location == ARGS_IN_REGISTERS) { |
8146 __ mov(scratch, eax); | |
8147 } else { | |
8148 __ mov(scratch, Operand(esp, 1 * kPointerSize)); | |
8149 } | |
7761 __ test(scratch, Immediate(kSmiTagMask)); | 8150 __ test(scratch, Immediate(kSmiTagMask)); |
7762 __ j(zero, &load_smi_2, not_taken); | 8151 __ j(zero, &load_smi_2, not_taken); |
7763 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); | 8152 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); |
7764 __ jmp(&done); | 8153 __ jmp(&done); |
7765 | 8154 |
7766 __ bind(&load_smi_1); | 8155 __ bind(&load_smi_1); |
7767 __ SmiUntag(scratch); | 8156 __ SmiUntag(scratch); |
7768 __ push(scratch); | 8157 __ push(scratch); |
7769 __ fild_s(Operand(esp, 0)); | 8158 __ fild_s(Operand(esp, 0)); |
7770 __ pop(scratch); | 8159 __ pop(scratch); |
7771 __ jmp(&done_load_1); | 8160 __ jmp(&done_load_1); |
7772 | 8161 |
7773 __ bind(&load_smi_2); | 8162 __ bind(&load_smi_2); |
7774 __ SmiUntag(scratch); | 8163 __ SmiUntag(scratch); |
7775 __ push(scratch); | 8164 __ push(scratch); |
7776 __ fild_s(Operand(esp, 0)); | 8165 __ fild_s(Operand(esp, 0)); |
7777 __ pop(scratch); | 8166 __ pop(scratch); |
7778 | 8167 |
7779 __ bind(&done); | 8168 __ bind(&done); |
7780 } | 8169 } |
7781 | 8170 |
7782 | 8171 |
8172 void FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm, | |
8173 Register scratch, | |
8174 ArgsLocation args_location) { | |
8175 if (args_location == ARGS_IN_REGISTERS) { | |
8176 __ mov(scratch, eax); | |
8177 } else { | |
8178 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | |
8179 } | |
8180 __ SmiUntag(scratch); | |
8181 __ push(scratch); | |
8182 __ fild_s(Operand(esp, 0)); | |
8183 __ pop(scratch); | |
8184 | |
8185 if (args_location == ARGS_IN_REGISTERS) { | |
8186 __ mov(scratch, ebx); | |
8187 } else { | |
8188 __ mov(scratch, Operand(esp, 1 * kPointerSize)); | |
8189 } | |
8190 __ SmiUntag(scratch); | |
8191 __ push(scratch); | |
8192 __ fild_s(Operand(esp, 0)); | |
8193 __ pop(scratch); | |
8194 } | |
8195 | |
8196 | |
7783 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, | 8197 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
7784 Label* non_float, | 8198 Label* non_float, |
7785 Register scratch) { | 8199 Register scratch) { |
7786 Label test_other, done; | 8200 Label test_other, done; |
7787 // Test if both operands are floats or smi -> scratch=k_is_float; | 8201 // Test if both operands are floats or smi -> scratch=k_is_float; |
7788 // Otherwise scratch = k_not_float. | 8202 // Otherwise scratch = k_not_float. |
7789 __ test(edx, Immediate(kSmiTagMask)); | 8203 __ test(edx, Immediate(kSmiTagMask)); |
7790 __ j(zero, &test_other, not_taken); // argument in edx is OK | 8204 __ j(zero, &test_other, not_taken); // argument in edx is OK |
7791 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); | 8205 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); |
7792 __ cmp(scratch, Factory::heap_number_map()); | 8206 __ cmp(scratch, Factory::heap_number_map()); |
(...skipping 1996 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9789 | 10203 |
9790 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 10204 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
9791 // tagged as a small integer. | 10205 // tagged as a small integer. |
9792 __ bind(&runtime); | 10206 __ bind(&runtime); |
9793 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 10207 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
9794 } | 10208 } |
9795 | 10209 |
9796 #undef __ | 10210 #undef __ |
9797 | 10211 |
9798 } } // namespace v8::internal | 10212 } } // namespace v8::internal |
OLD | NEW |