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