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 ArgLocation { | |
745 ARGS_ON_STACK, | |
746 ARGS_IN_REGISTERS | |
747 }; | |
748 | |
749 | |
750 class FloatingPointHelper : public AllStatic { | 744 class FloatingPointHelper : public AllStatic { |
751 public: | 745 public: |
| 746 |
| 747 enum ArgLocation { |
| 748 ARGS_ON_STACK, |
| 749 ARGS_IN_REGISTERS |
| 750 }; |
| 751 |
752 // Code pattern for loading a floating point value. Input value must | 752 // Code pattern for loading a floating point value. Input value must |
753 // 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: |
754 // operand in register number. Returns operand as floating point number | 754 // operand in register number. Returns operand as floating point number |
755 // on FPU stack. | 755 // on FPU stack. |
756 static void LoadFloatOperand(MacroAssembler* masm, Register number); | 756 static void LoadFloatOperand(MacroAssembler* masm, Register number); |
757 // Code pattern for loading floating point values. Input values must | 757 // Code pattern for loading floating point values. Input values must |
758 // be either smi or heap number objects (fp values). Requirements: | 758 // be either smi or heap number objects (fp values). Requirements: |
759 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. | 759 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. |
760 // Returns operands as floating point numbers on FPU stack. | 760 // Returns operands as floating point numbers on FPU stack. |
761 static void LoadFloatOperands(MacroAssembler* masm, | 761 static void LoadFloatOperands(MacroAssembler* masm, |
(...skipping 6308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7070 SetArgsInRegisters(); | 7070 SetArgsInRegisters(); |
7071 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 7071 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); |
7072 } | 7072 } |
7073 | 7073 |
7074 // Call the stub. | 7074 // Call the stub. |
7075 __ CallStub(this); | 7075 __ CallStub(this); |
7076 } | 7076 } |
7077 | 7077 |
7078 | 7078 |
7079 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { | 7079 void GenericBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, Label* slow) { |
7080 if (HasArgumentsInRegisters()) { | 7080 if (HasArgsInRegisters()) { |
7081 __ mov(ebx, eax); | 7081 __ mov(ebx, eax); |
7082 __ mov(eax, edx); | 7082 __ mov(eax, edx); |
7083 } else { | 7083 } else { |
7084 __ mov(ebx, Operand(esp, 1 * kPointerSize)); | 7084 __ mov(ebx, Operand(esp, 1 * kPointerSize)); |
7085 __ mov(eax, Operand(esp, 2 * kPointerSize)); | 7085 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
7086 } | 7086 } |
7087 | 7087 |
7088 Label not_smis, not_smis_or_overflow, not_smis_undo_optimistic; | 7088 Label not_smis, not_smis_or_overflow, not_smis_undo_optimistic; |
7089 Label use_fp_on_smis, done; | 7089 Label use_fp_on_smis, done; |
7090 | 7090 |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7242 | 7242 |
7243 __ bind(&use_fp_on_smis); | 7243 __ bind(&use_fp_on_smis); |
7244 // Both operands are known to be SMIs but the result does not fit into a SMI. | 7244 // Both operands are known to be SMIs but the result does not fit into a SMI. |
7245 switch (op_) { | 7245 switch (op_) { |
7246 case Token::ADD: | 7246 case Token::ADD: |
7247 case Token::SUB: | 7247 case Token::SUB: |
7248 case Token::MUL: | 7248 case Token::MUL: |
7249 case Token::DIV: { | 7249 case Token::DIV: { |
7250 Label after_alloc_failure; | 7250 Label after_alloc_failure; |
7251 | 7251 |
7252 ArgLocation arg_location = | 7252 FloatingPointHelper::ArgLocation arg_location = |
7253 (op_ == Token::ADD || op_ == Token::SUB) ? | 7253 (op_ == Token::ADD || op_ == Token::SUB) ? |
7254 ARGS_IN_REGISTERS : | 7254 FloatingPointHelper::ARGS_IN_REGISTERS : |
7255 ARGS_ON_STACK; | 7255 FloatingPointHelper::ARGS_ON_STACK; |
7256 | 7256 |
7257 __ AllocateHeapNumber( | 7257 __ AllocateHeapNumber( |
7258 edx, | 7258 edx, |
7259 ecx, | 7259 ecx, |
7260 no_reg, | 7260 no_reg, |
7261 arg_location == ARGS_IN_REGISTERS ? &after_alloc_failure : slow); | 7261 arg_location == FloatingPointHelper::ARGS_IN_REGISTERS ? |
| 7262 &after_alloc_failure : |
| 7263 slow); |
7262 | 7264 |
7263 if (CpuFeatures::IsSupported(SSE2)) { | 7265 if (CpuFeatures::IsSupported(SSE2)) { |
7264 CpuFeatures::Scope use_sse2(SSE2); | 7266 CpuFeatures::Scope use_sse2(SSE2); |
7265 FloatingPointHelper::LoadSse2Smis(masm, ecx, arg_location); | 7267 FloatingPointHelper::LoadSse2Smis(masm, ecx, arg_location); |
7266 switch (op_) { | 7268 switch (op_) { |
7267 case Token::ADD: __ addsd(xmm0, xmm1); break; | 7269 case Token::ADD: __ addsd(xmm0, xmm1); break; |
7268 case Token::SUB: __ subsd(xmm0, xmm1); break; | 7270 case Token::SUB: __ subsd(xmm0, xmm1); break; |
7269 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 7271 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
7270 case Token::DIV: __ divsd(xmm0, xmm1); break; | 7272 case Token::DIV: __ divsd(xmm0, xmm1); break; |
7271 default: UNREACHABLE(); | 7273 default: UNREACHABLE(); |
7272 } | 7274 } |
7273 __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); | 7275 __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); |
7274 } else { // SSE2 not available, use FPU. | 7276 } else { // SSE2 not available, use FPU. |
7275 FloatingPointHelper::LoadFloatSmis(masm, ecx, arg_location); | 7277 FloatingPointHelper::LoadFloatSmis(masm, ecx, arg_location); |
7276 switch (op_) { | 7278 switch (op_) { |
7277 case Token::ADD: __ faddp(1); break; | 7279 case Token::ADD: __ faddp(1); break; |
7278 case Token::SUB: __ fsubp(1); break; | 7280 case Token::SUB: __ fsubp(1); break; |
7279 case Token::MUL: __ fmulp(1); break; | 7281 case Token::MUL: __ fmulp(1); break; |
7280 case Token::DIV: __ fdivp(1); break; | 7282 case Token::DIV: __ fdivp(1); break; |
7281 default: UNREACHABLE(); | 7283 default: UNREACHABLE(); |
7282 } | 7284 } |
7283 __ fstp_d(FieldOperand(edx, HeapNumber::kValueOffset)); | 7285 __ fstp_d(FieldOperand(edx, HeapNumber::kValueOffset)); |
7284 } | 7286 } |
7285 __ mov(eax, edx); | 7287 __ mov(eax, edx); |
7286 GenerateReturn(masm); | 7288 GenerateReturn(masm); |
7287 | 7289 |
7288 if (arg_location == ARGS_IN_REGISTERS) { | 7290 if (arg_location == FloatingPointHelper::ARGS_IN_REGISTERS) { |
7289 __ bind(&after_alloc_failure); | 7291 __ bind(&after_alloc_failure); |
7290 __ mov(edx, eax); | 7292 __ mov(edx, eax); |
7291 __ mov(eax, ebx); | 7293 __ mov(eax, ebx); |
7292 __ jmp(slow); | 7294 __ jmp(slow); |
7293 } | 7295 } |
| 7296 break; |
7294 } | 7297 } |
| 7298 |
7295 case Token::BIT_OR: | 7299 case Token::BIT_OR: |
7296 case Token::BIT_AND: | 7300 case Token::BIT_AND: |
7297 case Token::BIT_XOR: | 7301 case Token::BIT_XOR: |
7298 case Token::SAR: | 7302 case Token::SAR: |
7299 // Do nothing here as these operations always succeed on a pair of smis. | 7303 // Do nothing here as these operations always succeed on a pair of smis. |
7300 break; | 7304 break; |
7301 | 7305 |
7302 case Token::MOD: | 7306 case Token::MOD: |
7303 case Token::SHR: | 7307 case Token::SHR: |
7304 // Do nothing here as these go directly to runtime. | 7308 // Do nothing here as these go directly to runtime. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7368 case Token::SUB: __ subsd(xmm0, xmm1); break; | 7372 case Token::SUB: __ subsd(xmm0, xmm1); break; |
7369 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 7373 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
7370 case Token::DIV: __ divsd(xmm0, xmm1); break; | 7374 case Token::DIV: __ divsd(xmm0, xmm1); break; |
7371 default: UNREACHABLE(); | 7375 default: UNREACHABLE(); |
7372 } | 7376 } |
7373 GenerateHeapResultAllocation(masm, &call_runtime); | 7377 GenerateHeapResultAllocation(masm, &call_runtime); |
7374 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 7378 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
7375 GenerateReturn(masm); | 7379 GenerateReturn(masm); |
7376 } else { // SSE2 not available, use FPU. | 7380 } else { // SSE2 not available, use FPU. |
7377 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 7381 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
7378 FloatingPointHelper::LoadFloatOperands(masm, ecx, ARGS_IN_REGISTERS); | 7382 FloatingPointHelper::LoadFloatOperands( |
| 7383 masm, |
| 7384 ecx, |
| 7385 FloatingPointHelper::ARGS_IN_REGISTERS); |
7379 switch (op_) { | 7386 switch (op_) { |
7380 case Token::ADD: __ faddp(1); break; | 7387 case Token::ADD: __ faddp(1); break; |
7381 case Token::SUB: __ fsubp(1); break; | 7388 case Token::SUB: __ fsubp(1); break; |
7382 case Token::MUL: __ fmulp(1); break; | 7389 case Token::MUL: __ fmulp(1); break; |
7383 case Token::DIV: __ fdivp(1); break; | 7390 case Token::DIV: __ fdivp(1); break; |
7384 default: UNREACHABLE(); | 7391 default: UNREACHABLE(); |
7385 } | 7392 } |
7386 Label after_alloc_failure; | 7393 Label after_alloc_failure; |
7387 GenerateHeapResultAllocation(masm, &after_alloc_failure); | 7394 GenerateHeapResultAllocation(masm, &after_alloc_failure); |
7388 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 7395 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7462 } | 7469 } |
7463 break; | 7470 break; |
7464 } | 7471 } |
7465 default: UNREACHABLE(); break; | 7472 default: UNREACHABLE(); break; |
7466 } | 7473 } |
7467 | 7474 |
7468 // If all else fails, use the runtime system to get the correct | 7475 // If all else fails, use the runtime system to get the correct |
7469 // result. If arguments was passed in registers now place them on the | 7476 // result. If arguments was passed in registers now place them on the |
7470 // stack in the correct order below the return address. | 7477 // stack in the correct order below the return address. |
7471 __ bind(&call_runtime); | 7478 __ bind(&call_runtime); |
7472 if (HasArgumentsInRegisters()) { | 7479 if (HasArgsInRegisters()) { |
7473 __ pop(ecx); | 7480 __ pop(ecx); |
7474 if (HasArgumentsReversed()) { | 7481 if (HasArgsReversed()) { |
7475 __ push(eax); | 7482 __ push(eax); |
7476 __ push(edx); | 7483 __ push(edx); |
7477 } else { | 7484 } else { |
7478 __ push(edx); | 7485 __ push(edx); |
7479 __ push(eax); | 7486 __ push(eax); |
7480 } | 7487 } |
7481 __ push(ecx); | 7488 __ push(ecx); |
7482 } | 7489 } |
7483 switch (op_) { | 7490 switch (op_) { |
7484 case Token::ADD: { | 7491 case Token::ADD: { |
(...skipping 11 matching lines...) Expand all Loading... |
7496 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | 7503 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); |
7497 __ j(above_equal, &string1); | 7504 __ j(above_equal, &string1); |
7498 | 7505 |
7499 // First and second argument are strings. Jump to the string add stub. | 7506 // First and second argument are strings. Jump to the string add stub. |
7500 StringAddStub stub(NO_STRING_CHECK_IN_STUB); | 7507 StringAddStub stub(NO_STRING_CHECK_IN_STUB); |
7501 __ TailCallStub(&stub); | 7508 __ TailCallStub(&stub); |
7502 | 7509 |
7503 // Only first argument is a string. | 7510 // Only first argument is a string. |
7504 __ bind(&string1); | 7511 __ bind(&string1); |
7505 __ InvokeBuiltin( | 7512 __ InvokeBuiltin( |
7506 HasArgumentsReversed() ? | 7513 HasArgsReversed() ? |
7507 Builtins::STRING_ADD_RIGHT : | 7514 Builtins::STRING_ADD_RIGHT : |
7508 Builtins::STRING_ADD_LEFT, | 7515 Builtins::STRING_ADD_LEFT, |
7509 JUMP_FUNCTION); | 7516 JUMP_FUNCTION); |
7510 | 7517 |
7511 // First argument was not a string, test second. | 7518 // First argument was not a string, test second. |
7512 __ bind(¬_string1); | 7519 __ bind(¬_string1); |
7513 __ test(eax, Immediate(kSmiTagMask)); | 7520 __ test(eax, Immediate(kSmiTagMask)); |
7514 __ j(zero, ¬_strings); | 7521 __ j(zero, ¬_strings); |
7515 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | 7522 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); |
7516 __ j(above_equal, ¬_strings); | 7523 __ j(above_equal, ¬_strings); |
7517 | 7524 |
7518 // Only second argument is a string. | 7525 // Only second argument is a string. |
7519 __ InvokeBuiltin( | 7526 __ InvokeBuiltin( |
7520 HasArgumentsReversed() ? | 7527 HasArgsReversed() ? |
7521 Builtins::STRING_ADD_LEFT : | 7528 Builtins::STRING_ADD_LEFT : |
7522 Builtins::STRING_ADD_RIGHT, | 7529 Builtins::STRING_ADD_RIGHT, |
7523 JUMP_FUNCTION); | 7530 JUMP_FUNCTION); |
7524 | 7531 |
7525 __ bind(¬_strings); | 7532 __ bind(¬_strings); |
7526 // Neither argument is a string. | 7533 // Neither argument is a string. |
7527 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | 7534 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); |
7528 break; | 7535 break; |
7529 } | 7536 } |
7530 case Token::SUB: | 7537 case Token::SUB: |
7531 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | 7538 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); |
7532 break; | 7539 break; |
7533 case Token::MUL: | 7540 case Token::MUL: |
(...skipping 26 matching lines...) Expand all Loading... |
7560 default: | 7567 default: |
7561 UNREACHABLE(); | 7568 UNREACHABLE(); |
7562 } | 7569 } |
7563 } | 7570 } |
7564 | 7571 |
7565 | 7572 |
7566 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, | 7573 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, |
7567 Label* alloc_failure) { | 7574 Label* alloc_failure) { |
7568 Label skip_allocation; | 7575 Label skip_allocation; |
7569 OverwriteMode mode = mode_; | 7576 OverwriteMode mode = mode_; |
7570 if (HasArgumentsReversed()) { | 7577 if (HasArgsReversed()) { |
7571 if (mode == OVERWRITE_RIGHT) { | 7578 if (mode == OVERWRITE_RIGHT) { |
7572 mode = OVERWRITE_LEFT; | 7579 mode = OVERWRITE_LEFT; |
7573 } else if (mode == OVERWRITE_LEFT) { | 7580 } else if (mode == OVERWRITE_LEFT) { |
7574 mode = OVERWRITE_RIGHT; | 7581 mode = OVERWRITE_RIGHT; |
7575 } | 7582 } |
7576 } | 7583 } |
7577 switch (mode) { | 7584 switch (mode) { |
7578 case OVERWRITE_LEFT: { | 7585 case OVERWRITE_LEFT: { |
7579 // If the argument in edx is already an object, we skip the | 7586 // If the argument in edx is already an object, we skip the |
7580 // allocation of a heap number. | 7587 // allocation of a heap number. |
(...skipping 25 matching lines...) Expand all Loading... |
7606 __ mov(eax, ebx); | 7613 __ mov(eax, ebx); |
7607 __ bind(&skip_allocation); | 7614 __ bind(&skip_allocation); |
7608 break; | 7615 break; |
7609 default: UNREACHABLE(); | 7616 default: UNREACHABLE(); |
7610 } | 7617 } |
7611 } | 7618 } |
7612 | 7619 |
7613 | 7620 |
7614 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { | 7621 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
7615 // If arguments are not passed in registers read them from the stack. | 7622 // If arguments are not passed in registers read them from the stack. |
7616 if (!HasArgumentsInRegisters()) { | 7623 if (!HasArgsInRegisters()) { |
7617 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 7624 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
7618 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 7625 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
7619 } | 7626 } |
7620 } | 7627 } |
7621 | 7628 |
7622 | 7629 |
7623 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { | 7630 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { |
7624 // If arguments are not passed in registers remove them from the stack before | 7631 // If arguments are not passed in registers remove them from the stack before |
7625 // returning. | 7632 // returning. |
7626 if (!HasArgumentsInRegisters()) { | 7633 if (!HasArgsInRegisters()) { |
7627 __ ret(2 * kPointerSize); // Remove both operands | 7634 __ ret(2 * kPointerSize); // Remove both operands |
7628 } else { | 7635 } else { |
7629 __ ret(0); | 7636 __ ret(0); |
7630 } | 7637 } |
7631 } | 7638 } |
7632 | 7639 |
7633 | 7640 |
7634 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 7641 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
7635 // is faster than using the built-in instructions on floating point registers. | 7642 // is faster than using the built-in instructions on floating point registers. |
7636 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 7643 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
(...skipping 2344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9981 | 9988 |
9982 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 9989 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
9983 // tagged as a small integer. | 9990 // tagged as a small integer. |
9984 __ bind(&runtime); | 9991 __ bind(&runtime); |
9985 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 9992 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
9986 } | 9993 } |
9987 | 9994 |
9988 #undef __ | 9995 #undef __ |
9989 | 9996 |
9990 } } // namespace v8::internal | 9997 } } // namespace v8::internal |
OLD | NEW |