OLD | NEW |
---|---|
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 8318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8329 const char* op_name = Token::Name(op_); | 8329 const char* op_name = Token::Name(op_); |
8330 const char* overwrite_name; | 8330 const char* overwrite_name; |
8331 switch (mode_) { | 8331 switch (mode_) { |
8332 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 8332 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
8333 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 8333 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
8334 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 8334 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
8335 default: overwrite_name = "UnknownOverwrite"; break; | 8335 default: overwrite_name = "UnknownOverwrite"; break; |
8336 } | 8336 } |
8337 | 8337 |
8338 OS::SNPrintF(Vector<char>(name_, len), | 8338 OS::SNPrintF(Vector<char>(name_, len), |
8339 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s", | 8339 "GenericBinaryOpStub_%s_%s%s_%s%s_%s%s_%s", |
8340 op_name, | 8340 op_name, |
8341 overwrite_name, | 8341 overwrite_name, |
8342 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 8342 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
8343 args_in_registers_ ? "RegArgs" : "StackArgs", | 8343 args_in_registers_ ? "RegArgs" : "StackArgs", |
8344 args_reversed_ ? "_R" : "", | 8344 args_reversed_ ? "_R" : "", |
8345 use_sse3_ ? "SSE3" : "SSE2", | 8345 use_sse3_ ? "SSE3" : "SSE2", |
8346 operands_type_.ToString()); | 8346 static_operands_type_.ToString(), |
8347 BinaryOpIC::GetName(runtime_operands_type_)); | |
8347 return name_; | 8348 return name_; |
8348 } | 8349 } |
8349 | 8350 |
8350 | 8351 |
8351 void GenericBinaryOpStub::GenerateCall( | 8352 void GenericBinaryOpStub::GenerateCall( |
8352 MacroAssembler* masm, | 8353 MacroAssembler* masm, |
8353 Register left, | 8354 Register left, |
8354 Register right) { | 8355 Register right) { |
8355 if (!ArgsInRegistersSupported()) { | 8356 if (!ArgsInRegistersSupported()) { |
8356 // Pass arguments on the stack. | 8357 // Pass arguments on the stack. |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8647 break; | 8648 break; |
8648 | 8649 |
8649 default: | 8650 default: |
8650 break; | 8651 break; |
8651 } | 8652 } |
8652 } | 8653 } |
8653 | 8654 |
8654 | 8655 |
8655 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 8656 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
8656 Label call_runtime; | 8657 Label call_runtime; |
8657 if (HasSmiCodeInStub()) { | 8658 |
8659 if (ShouldGenerateSmiCode()) { | |
8658 GenerateSmiCode(masm, &call_runtime); | 8660 GenerateSmiCode(masm, &call_runtime); |
8659 } else if (op_ != Token::MOD) { | 8661 } else if (op_ != Token::MOD) { |
8660 GenerateLoadArguments(masm); | 8662 if (!HasArgsInRegisters()) { |
8663 GenerateLoadArguments(masm); | |
8664 } | |
8661 } | 8665 } |
8662 // Floating point case. | 8666 // Floating point case. |
8663 switch (op_) { | 8667 if (ShouldGenerateFPCode()) { |
8664 case Token::ADD: | 8668 switch (op_) { |
8665 case Token::SUB: | 8669 case Token::ADD: |
8666 case Token::MUL: | 8670 case Token::SUB: |
8667 case Token::DIV: { | 8671 case Token::MUL: |
8668 // rax: y | 8672 case Token::DIV: { |
8669 // rdx: x | 8673 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
8670 if (operands_type_.IsNumber()) { | 8674 HasSmiCodeInStub()) { |
8675 // Execution reaches this point when the first non-smi argument occurs | |
8676 // (and only if smi code is generated). This is the right moment to | |
8677 // patch to HEAP_NUMBERS state. The transition is attempted only for | |
8678 // the four basic operations. The stub stays in the DEFAULT state | |
8679 // forever for all other operations (also if smi code is skipped). | |
8680 GenerateTypeTransition(masm); | |
8681 } | |
8682 | |
8683 Label not_floats; | |
8684 // rax: y | |
8685 // rdx: x | |
8686 if (static_operands_type_.IsNumber()) { | |
8671 if (FLAG_debug_code) { | 8687 if (FLAG_debug_code) { |
8672 // Assert at runtime that inputs are only numbers. | 8688 // Assert at runtime that inputs are only numbers. |
8673 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); | 8689 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); |
8674 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); | 8690 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); |
8675 } | 8691 } |
8676 } else { | 8692 } else { |
8677 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); | 8693 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); |
8678 } | 8694 } |
8679 // Fast-case: Both operands are numbers. | 8695 // Fast-case: Both operands are numbers. |
8680 // xmm4 and xmm5 are volatile XMM registers. | 8696 // xmm4 and xmm5 are volatile XMM registers. |
8681 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); | 8697 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); |
8682 | 8698 |
8683 switch (op_) { | 8699 switch (op_) { |
8684 case Token::ADD: __ addsd(xmm4, xmm5); break; | 8700 case Token::ADD: __ addsd(xmm4, xmm5); break; |
8685 case Token::SUB: __ subsd(xmm4, xmm5); break; | 8701 case Token::SUB: __ subsd(xmm4, xmm5); break; |
8686 case Token::MUL: __ mulsd(xmm4, xmm5); break; | 8702 case Token::MUL: __ mulsd(xmm4, xmm5); break; |
8687 case Token::DIV: __ divsd(xmm4, xmm5); break; | 8703 case Token::DIV: __ divsd(xmm4, xmm5); break; |
8688 default: UNREACHABLE(); | 8704 default: UNREACHABLE(); |
8689 } | |
8690 // Allocate a heap number, if needed. | |
8691 Label skip_allocation; | |
8692 OverwriteMode mode = mode_; | |
8693 if (HasArgsReversed()) { | |
8694 if (mode == OVERWRITE_RIGHT) { | |
8695 mode = OVERWRITE_LEFT; | |
8696 } else if (mode == OVERWRITE_LEFT) { | |
8697 mode = OVERWRITE_RIGHT; | |
8698 } | 8705 } |
8699 } | 8706 // Allocate a heap number, if needed. |
8700 switch (mode) { | 8707 Label skip_allocation; |
8701 case OVERWRITE_LEFT: | 8708 OverwriteMode mode = mode_; |
8702 __ JumpIfNotSmi(rdx, &skip_allocation); | 8709 if (HasArgsReversed()) { |
8703 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | 8710 if (mode == OVERWRITE_RIGHT) { |
8704 __ movq(rdx, rbx); | 8711 mode = OVERWRITE_LEFT; |
8705 __ bind(&skip_allocation); | 8712 } else if (mode == OVERWRITE_LEFT) { |
8706 __ movq(rax, rdx); | 8713 mode = OVERWRITE_RIGHT; |
8707 break; | 8714 } |
8708 case OVERWRITE_RIGHT: | 8715 } |
8709 // If the argument in rax is already an object, we skip the | 8716 switch (mode) { |
8710 // allocation of a heap number. | |
8711 __ JumpIfNotSmi(rax, &skip_allocation); | |
8712 // Fall through! | |
8713 case NO_OVERWRITE: | |
8714 // Allocate a heap number for the result. Keep rax and rdx intact | |
8715 // for the possible runtime call. | |
8716 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | |
8717 __ movq(rax, rbx); | |
8718 __ bind(&skip_allocation); | |
8719 break; | |
8720 default: UNREACHABLE(); | |
8721 } | |
8722 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); | |
8723 GenerateReturn(masm); | |
8724 } | |
8725 case Token::MOD: { | |
8726 // For MOD we go directly to runtime in the non-smi case. | |
8727 break; | |
8728 } | |
8729 case Token::BIT_OR: | |
8730 case Token::BIT_AND: | |
8731 case Token::BIT_XOR: | |
8732 case Token::SAR: | |
8733 case Token::SHL: | |
8734 case Token::SHR: { | |
8735 Label skip_allocation, non_smi_result; | |
8736 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | |
8737 switch (op_) { | |
8738 case Token::BIT_OR: __ orl(rax, rcx); break; | |
8739 case Token::BIT_AND: __ andl(rax, rcx); break; | |
8740 case Token::BIT_XOR: __ xorl(rax, rcx); break; | |
8741 case Token::SAR: __ sarl_cl(rax); break; | |
8742 case Token::SHL: __ shll_cl(rax); break; | |
8743 case Token::SHR: __ shrl_cl(rax); break; | |
8744 default: UNREACHABLE(); | |
8745 } | |
8746 if (op_ == Token::SHR) { | |
8747 // Check if result is non-negative. This can only happen for a shift | |
8748 // by zero, which also doesn't update the sign flag. | |
8749 __ testl(rax, rax); | |
8750 __ j(negative, &non_smi_result); | |
8751 } | |
8752 __ JumpIfNotValidSmiValue(rax, &non_smi_result); | |
8753 // Tag smi result, if possible, and return. | |
8754 __ Integer32ToSmi(rax, rax); | |
8755 GenerateReturn(masm); | |
8756 | |
8757 // All ops except SHR return a signed int32 that we load in a HeapNumber. | |
8758 if (op_ != Token::SHR && non_smi_result.is_linked()) { | |
8759 __ bind(&non_smi_result); | |
8760 // Allocate a heap number if needed. | |
8761 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result | |
8762 switch (mode_) { | |
8763 case OVERWRITE_LEFT: | 8717 case OVERWRITE_LEFT: |
8718 __ JumpIfNotSmi(rdx, &skip_allocation); | |
8719 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | |
8720 __ movq(rdx, rbx); | |
8721 __ bind(&skip_allocation); | |
8722 __ movq(rax, rdx); | |
8723 break; | |
8764 case OVERWRITE_RIGHT: | 8724 case OVERWRITE_RIGHT: |
8765 // If the operand was an object, we skip the | 8725 // If the argument in rax is already an object, we skip the |
8766 // allocation of a heap number. | 8726 // allocation of a heap number. |
8767 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? | |
8768 1 * kPointerSize : 2 * kPointerSize)); | |
8769 __ JumpIfNotSmi(rax, &skip_allocation); | 8727 __ JumpIfNotSmi(rax, &skip_allocation); |
8770 // Fall through! | 8728 // Fall through! |
8771 case NO_OVERWRITE: | 8729 case NO_OVERWRITE: |
8772 __ AllocateHeapNumber(rax, rcx, &call_runtime); | 8730 // Allocate a heap number for the result. Keep rax and rdx intact |
8731 // for the possible runtime call. | |
8732 __ AllocateHeapNumber(rbx, rcx, &call_runtime); | |
8733 __ movq(rax, rbx); | |
8773 __ bind(&skip_allocation); | 8734 __ bind(&skip_allocation); |
8774 break; | 8735 break; |
8775 default: UNREACHABLE(); | 8736 default: UNREACHABLE(); |
8776 } | 8737 } |
8777 // Store the result in the HeapNumber and return. | 8738 __ movsd(FieldOperand(rax, HeapNumber::kValueOffset), xmm4); |
8778 __ movq(Operand(rsp, 1 * kPointerSize), rbx); | |
8779 __ fild_s(Operand(rsp, 1 * kPointerSize)); | |
8780 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | |
8781 GenerateReturn(masm); | 8739 GenerateReturn(masm); |
8740 __ bind(¬_floats); | |
8741 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && | |
8742 !HasSmiCodeInStub()) { | |
8743 // Execution reaches this point when the first non-number argument | |
8744 // occurs (and only if smi code is skipped from the stub, otherwise | |
8745 // the patching has already been done earlier in this case branch). | |
8746 // A perfect moment to try patching to STRINGS for ADD operation. | |
8747 if (op_ == Token::ADD) { | |
Mads Ager (chromium)
2010/03/17 10:10:59
Indentation is off here.
Vladislav Kaznacheev
2010/03/18 11:14:23
Done.
| |
8748 GenerateTypeTransition(masm); | |
8749 } | |
8750 } | |
8751 break; | |
8782 } | 8752 } |
8753 case Token::MOD: { | |
8754 // For MOD we go directly to runtime in the non-smi case. | |
8755 break; | |
8756 } | |
8757 case Token::BIT_OR: | |
8758 case Token::BIT_AND: | |
8759 case Token::BIT_XOR: | |
8760 case Token::SAR: | |
8761 case Token::SHL: | |
8762 case Token::SHR: { | |
8763 Label skip_allocation, non_smi_result; | |
8764 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | |
8765 switch (op_) { | |
8766 case Token::BIT_OR: __ orl(rax, rcx); break; | |
8767 case Token::BIT_AND: __ andl(rax, rcx); break; | |
8768 case Token::BIT_XOR: __ xorl(rax, rcx); break; | |
8769 case Token::SAR: __ sarl_cl(rax); break; | |
8770 case Token::SHL: __ shll_cl(rax); break; | |
8771 case Token::SHR: __ shrl_cl(rax); break; | |
8772 default: UNREACHABLE(); | |
8773 } | |
8774 if (op_ == Token::SHR) { | |
8775 // Check if result is non-negative. This can only happen for a shift | |
8776 // by zero, which also doesn't update the sign flag. | |
8777 __ testl(rax, rax); | |
8778 __ j(negative, &non_smi_result); | |
8779 } | |
8780 __ JumpIfNotValidSmiValue(rax, &non_smi_result); | |
8781 // Tag smi result, if possible, and return. | |
8782 __ Integer32ToSmi(rax, rax); | |
8783 GenerateReturn(masm); | |
8783 | 8784 |
8784 // SHR should return uint32 - go to runtime for non-smi/negative result. | 8785 // All ops except SHR return a signed int32 that we load in |
8785 if (op_ == Token::SHR) { | 8786 // a HeapNumber. |
8786 __ bind(&non_smi_result); | 8787 if (op_ != Token::SHR && non_smi_result.is_linked()) { |
8788 __ bind(&non_smi_result); | |
8789 // Allocate a heap number if needed. | |
8790 __ movsxlq(rbx, rax); // rbx: sign extended 32-bit result | |
8791 switch (mode_) { | |
8792 case OVERWRITE_LEFT: | |
8793 case OVERWRITE_RIGHT: | |
8794 // If the operand was an object, we skip the | |
8795 // allocation of a heap number. | |
8796 __ movq(rax, Operand(rsp, mode_ == OVERWRITE_RIGHT ? | |
8797 1 * kPointerSize : 2 * kPointerSize)); | |
8798 __ JumpIfNotSmi(rax, &skip_allocation); | |
8799 // Fall through! | |
8800 case NO_OVERWRITE: | |
8801 __ AllocateHeapNumber(rax, rcx, &call_runtime); | |
8802 __ bind(&skip_allocation); | |
8803 break; | |
8804 default: UNREACHABLE(); | |
8805 } | |
8806 // Store the result in the HeapNumber and return. | |
8807 __ movq(Operand(rsp, 1 * kPointerSize), rbx); | |
8808 __ fild_s(Operand(rsp, 1 * kPointerSize)); | |
8809 __ fstp_d(FieldOperand(rax, HeapNumber::kValueOffset)); | |
8810 GenerateReturn(masm); | |
8811 } | |
8812 | |
8813 // SHR should return uint32 - go to runtime for non-smi/negative result. | |
8814 if (op_ == Token::SHR) { | |
8815 __ bind(&non_smi_result); | |
8816 } | |
8817 break; | |
8787 } | 8818 } |
8788 break; | 8819 default: UNREACHABLE(); break; |
8789 } | 8820 } |
8790 default: UNREACHABLE(); break; | |
8791 } | 8821 } |
8792 | 8822 |
8793 // If all else fails, use the runtime system to get the correct | 8823 // If all else fails, use the runtime system to get the correct |
8794 // result. If arguments was passed in registers now place them on the | 8824 // result. If arguments was passed in registers now place them on the |
8795 // stack in the correct order below the return address. | 8825 // stack in the correct order below the return address. |
8796 __ bind(&call_runtime); | 8826 __ bind(&call_runtime); |
8797 if (HasArgsInRegisters()) { | 8827 if (HasArgsInRegisters()) { |
8798 __ pop(rcx); | 8828 GenerateRegisterArgsPush(masm); |
8799 if (HasArgsReversed()) { | |
8800 __ push(rax); | |
8801 __ push(rdx); | |
8802 } else { | |
8803 __ push(rdx); | |
8804 __ push(rax); | |
8805 } | |
8806 __ push(rcx); | |
8807 } | 8829 } |
8830 | |
8808 switch (op_) { | 8831 switch (op_) { |
8809 case Token::ADD: { | 8832 case Token::ADD: { |
8810 // Test for string arguments before calling runtime. | 8833 // Test for string arguments before calling runtime. |
8811 Label not_strings, both_strings, not_string1, string1; | 8834 Label not_strings, both_strings, not_string1, string1; |
8835 | |
8836 // If this stub has already generated FP-specific code then the arguments | |
8837 // are already in rdx, rax | |
8838 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { | |
8839 GenerateLoadArguments(masm); | |
8840 } | |
8841 | |
8812 Condition is_smi; | 8842 Condition is_smi; |
8813 Result answer; | |
8814 is_smi = masm->CheckSmi(rdx); | 8843 is_smi = masm->CheckSmi(rdx); |
8815 __ j(is_smi, ¬_string1); | 8844 __ j(is_smi, ¬_string1); |
8816 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); | 8845 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rdx); |
8817 __ j(above_equal, ¬_string1); | 8846 __ j(above_equal, ¬_string1); |
8818 | 8847 |
8819 // First argument is a a string, test second. | 8848 // First argument is a a string, test second. |
8820 is_smi = masm->CheckSmi(rax); | 8849 is_smi = masm->CheckSmi(rax); |
8821 __ j(is_smi, &string1); | 8850 __ j(is_smi, &string1); |
8822 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); | 8851 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rax); |
8823 __ j(above_equal, &string1); | 8852 __ j(above_equal, &string1); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
8879 break; | 8908 break; |
8880 case Token::SHL: | 8909 case Token::SHL: |
8881 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | 8910 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); |
8882 break; | 8911 break; |
8883 case Token::SHR: | 8912 case Token::SHR: |
8884 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 8913 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
8885 break; | 8914 break; |
8886 default: | 8915 default: |
8887 UNREACHABLE(); | 8916 UNREACHABLE(); |
8888 } | 8917 } |
8918 | |
8919 // Generate an unreachable reference to the DEFAULT stub so that it can be | |
Mads Ager (chromium)
2010/03/17 10:10:59
This still feels like a nasty hack to me. Does th
Vladislav Kaznacheev
2010/03/18 11:14:23
Added a TODO to experiment and remove.
On 2010/03/
| |
8920 // found at the end of this stub when clearing ICs at GC. | |
8921 if (runtime_operands_type_ != BinaryOpIC::DEFAULT) { | |
8922 GenericBinaryOpStub uninit(MinorKey(), BinaryOpIC::DEFAULT); | |
8923 __ TailCallStub(&uninit); | |
8924 } | |
8889 } | 8925 } |
8890 | 8926 |
8891 | 8927 |
8892 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { | 8928 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
8893 // If arguments are not passed in registers read them from the stack. | 8929 ASSERT(!HasArgsInRegisters()); |
8894 if (!HasArgsInRegisters()) { | 8930 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
8895 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 8931 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
8896 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); | |
8897 } | |
8898 } | 8932 } |
8899 | 8933 |
8900 | 8934 |
8901 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { | 8935 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { |
8902 // If arguments are not passed in registers remove them from the stack before | 8936 // If arguments are not passed in registers remove them from the stack before |
8903 // returning. | 8937 // returning. |
8904 if (!HasArgsInRegisters()) { | 8938 if (!HasArgsInRegisters()) { |
8905 __ ret(2 * kPointerSize); // Remove both operands | 8939 __ ret(2 * kPointerSize); // Remove both operands |
8906 } else { | 8940 } else { |
8907 __ ret(0); | 8941 __ ret(0); |
8908 } | 8942 } |
8909 } | 8943 } |
8910 | 8944 |
8911 | 8945 |
8946 void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
8947 ASSERT(HasArgsInRegisters()); | |
8948 __ pop(rcx); | |
8949 if (HasArgsReversed()) { | |
8950 __ push(rax); | |
8951 __ push(rdx); | |
8952 } else { | |
8953 __ push(rdx); | |
8954 __ push(rax); | |
8955 } | |
8956 __ push(rcx); | |
8957 } | |
8958 | |
8959 | |
8960 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | |
8961 Label get_result; | |
8962 | |
8963 // Keep a copy of operands on the stack and make sure they are also in | |
8964 // edx, eax. | |
Mads Ager (chromium)
2010/03/17 10:10:59
ia32 register names.
Vladislav Kaznacheev
2010/03/18 11:14:23
Done.
| |
8965 if (HasArgsInRegisters()) { | |
8966 GenerateRegisterArgsPush(masm); | |
8967 } else { | |
8968 GenerateLoadArguments(masm); | |
8969 } | |
8970 | |
8971 // Internal frame is necessary to handle exceptions properly. | |
8972 __ EnterInternalFrame(); | |
8973 | |
8974 // Push arguments on stack if the stub expects them there. | |
8975 if (!HasArgsInRegisters()) { | |
8976 __ push(rdx); | |
8977 __ push(rax); | |
8978 } | |
8979 // Call the stub proper to get the result in rax. | |
8980 __ call(&get_result); | |
8981 __ LeaveInternalFrame(); | |
8982 | |
8983 // Left and right arguments are already on stack. | |
8984 __ pop(rcx); | |
8985 // Push the operation result. The tail call to BinaryOp_Patch will | |
8986 // return it to the original caller.. | |
8987 __ push(rax); | |
8988 | |
8989 // Push this stub's key. | |
8990 __ movq(rax, Immediate(MinorKey())); | |
8991 __ Integer32ToSmi(rax, rax); | |
8992 __ push(rax); | |
8993 | |
8994 // Although the operation and the type info are encoded into the key, | |
8995 // the encoding is opaque, so push them too. | |
8996 __ movq(rax, Immediate(op_)); | |
8997 __ Integer32ToSmi(rax, rax); | |
8998 __ push(rax); | |
8999 | |
9000 __ movq(rax, Immediate(runtime_operands_type_)); | |
9001 __ Integer32ToSmi(rax, rax); | |
9002 __ push(rax); | |
9003 | |
9004 __ push(rcx); | |
9005 | |
9006 // Perform patching to an appropriate fast case and return the result. | |
9007 __ TailCallExternalReference( | |
9008 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), | |
9009 6, | |
9010 1); | |
9011 | |
9012 // The entry point for the result calculation is assumed to be immediately | |
9013 // after this sequence. | |
9014 __ bind(&get_result); | |
9015 } | |
9016 | |
9017 | |
8912 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { | 9018 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
8913 return Handle<Code>::null(); | 9019 GenericBinaryOpStub stub(key, type_info); |
9020 HandleScope scope; | |
Mads Ager (chromium)
2010/03/17 10:10:59
This returns a handle from a destroyed handle scop
Vladislav Kaznacheev
2010/03/18 11:14:23
Done.
| |
9021 return stub.GetCode(); | |
8914 } | 9022 } |
8915 | 9023 |
8916 | 9024 |
8917 int CompareStub::MinorKey() { | 9025 int CompareStub::MinorKey() { |
8918 // Encode the three parameters in a unique 16 bit value. | 9026 // Encode the three parameters in a unique 16 bit value. |
8919 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); | 9027 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); |
8920 int nnn_value = (never_nan_nan_ ? 2 : 0); | 9028 int nnn_value = (never_nan_nan_ ? 2 : 0); |
8921 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. | 9029 if (cc_ != equal) nnn_value = 0; // Avoid duplicate stubs. |
8922 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); | 9030 return (static_cast<unsigned>(cc_) << 2) | nnn_value | (strict_ ? 1 : 0); |
8923 } | 9031 } |
(...skipping 874 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
9798 // Call the function from C++. | 9906 // Call the function from C++. |
9799 return FUNCTION_CAST<ModuloFunction>(buffer); | 9907 return FUNCTION_CAST<ModuloFunction>(buffer); |
9800 } | 9908 } |
9801 | 9909 |
9802 #endif | 9910 #endif |
9803 | 9911 |
9804 | 9912 |
9805 #undef __ | 9913 #undef __ |
9806 | 9914 |
9807 } } // namespace v8::internal | 9915 } } // namespace v8::internal |
OLD | NEW |