Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1351)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 551093: Implementing inline caches for GenericBinaryOpStub. ... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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, &not_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, &not_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, &not_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, &not_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
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(&not_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, &not_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(&not_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, &not_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, &not_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(&not_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, &not_string1);
7513 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx);
7514 __ j(above_equal, &not_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(&not_string1);
7538 __ test(eax, Immediate(kSmiTagMask));
7539 __ j(zero, &not_strings);
7540 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
7541 __ j(above_equal, &not_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(&not_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, &not_string1);
7421 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, eax);
7422 __ j(above_equal, &not_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(&not_string1);
7440 __ test(edx, Immediate(kSmiTagMask));
7441 __ j(zero, &not_strings);
7442 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, edx);
7443 __ j(above_equal, &not_strings);
7444
7445 // Only second argument is a string.
7446 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION);
7447
7448 __ bind(&not_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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698