Chromium Code Reviews| 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 |