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 893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
904 enum ArgLocation { | 904 enum ArgLocation { |
905 ARGS_ON_STACK, | 905 ARGS_ON_STACK, |
906 ARGS_IN_REGISTERS | 906 ARGS_IN_REGISTERS |
907 }; | 907 }; |
908 | 908 |
909 // Code pattern for loading a floating point value. Input value must | 909 // Code pattern for loading a floating point value. Input value must |
910 // be either a smi or a heap number object (fp value). Requirements: | 910 // be either a smi or a heap number object (fp value). Requirements: |
911 // operand in register number. Returns operand as floating point number | 911 // operand in register number. Returns operand as floating point number |
912 // on FPU stack. | 912 // on FPU stack. |
913 static void LoadFloatOperand(MacroAssembler* masm, Register number); | 913 static void LoadFloatOperand(MacroAssembler* masm, Register number); |
914 | |
914 // Code pattern for loading floating point values. Input values must | 915 // Code pattern for loading floating point values. Input values must |
915 // be either smi or heap number objects (fp values). Requirements: | 916 // be either smi or heap number objects (fp values). Requirements: |
916 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. | 917 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. |
917 // Returns operands as floating point numbers on FPU stack. | 918 // Returns operands as floating point numbers on FPU stack. |
918 static void LoadFloatOperands(MacroAssembler* masm, | 919 static void LoadFloatOperands(MacroAssembler* masm, |
919 Register scratch, | 920 Register scratch, |
920 ArgLocation arg_location = ARGS_ON_STACK); | 921 ArgLocation arg_location = ARGS_ON_STACK); |
921 | 922 |
922 // Similar to LoadFloatOperand but assumes that both operands are smis. | 923 // Similar to LoadFloatOperand but assumes that both operands are smis. |
923 // Expects operands in edx, eax. | 924 // Expects operands in edx, eax. |
924 static void LoadFloatSmis(MacroAssembler* masm, Register scratch); | 925 static void LoadFloatSmis(MacroAssembler* masm, Register scratch); |
925 | 926 |
926 // Test if operands are smi or number objects (fp). Requirements: | 927 // Test if operands are smi or number objects (fp). Requirements: |
927 // operand_1 in eax, operand_2 in edx; falls through on float | 928 // operand_1 in eax, operand_2 in edx; falls through on float |
928 // operands, jumps to the non_float label otherwise. | 929 // operands, jumps to the non_float label otherwise. |
929 static void CheckFloatOperands(MacroAssembler* masm, | 930 static void CheckFloatOperands(MacroAssembler* masm, |
930 Label* non_float, | 931 Label* non_float, |
931 Register scratch); | 932 Register scratch); |
933 | |
932 // Takes the operands in edx and eax and loads them as integers in eax | 934 // Takes the operands in edx and eax and loads them as integers in eax |
933 // and ecx. | 935 // and ecx. |
934 static void LoadAsIntegers(MacroAssembler* masm, | 936 static void LoadAsIntegers(MacroAssembler* masm, |
935 NumberInfo number_info, | 937 NumberInfo number_info, |
936 bool use_sse3, | 938 bool use_sse3, |
937 Label* operand_conversion_failure); | 939 Label* operand_conversion_failure); |
938 static void LoadNumbersAsIntegers(MacroAssembler* masm, | 940 static void LoadNumbersAsIntegers(MacroAssembler* masm, |
939 NumberInfo number_info, | 941 NumberInfo number_info, |
940 bool use_sse3, | 942 bool use_sse3, |
941 Label* operand_conversion_failure); | 943 Label* operand_conversion_failure); |
942 static void LoadUnknownsAsIntegers(MacroAssembler* masm, | 944 static void LoadUnknownsAsIntegers(MacroAssembler* masm, |
943 bool use_sse3, | 945 bool use_sse3, |
944 Label* operand_conversion_failure); | 946 Label* operand_conversion_failure); |
945 | 947 |
946 // Test if operands are smis or heap numbers and load them | 948 // Test if operands are smis or heap numbers and load them |
947 // into xmm0 and xmm1 if they are. Operands are in edx and eax. | 949 // into xmm0 and xmm1 if they are. Operands are in edx and eax. |
948 // Leaves operands unchanged. | 950 // Leaves operands unchanged. |
949 static void LoadSSE2Operands(MacroAssembler* masm); | 951 static void LoadSSE2Operands(MacroAssembler* masm); |
952 | |
950 // Test if operands are numbers (smi or HeapNumber objects), and load | 953 // Test if operands are numbers (smi or HeapNumber objects), and load |
951 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | 954 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
952 // either operand is not a number. Operands are in edx and eax. | 955 // either operand is not a number. Operands are in edx and eax. |
953 // Leaves operands unchanged. | 956 // Leaves operands unchanged. |
954 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); | 957 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); |
955 | 958 |
956 // Similar to LoadSSE2Operands but assumes that both operands are smis. | 959 // Similar to LoadSSE2Operands but assumes that both operands are smis. |
957 // Expects operands in edx, eax. | 960 // Expects operands in edx, eax. |
958 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); | 961 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); |
959 }; | 962 }; |
(...skipping 1394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2354 | 2357 |
2355 static bool CouldBeNaN(const Result& result) { | 2358 static bool CouldBeNaN(const Result& result) { |
2356 if (result.number_info().IsSmi()) return false; | 2359 if (result.number_info().IsSmi()) return false; |
2357 if (result.number_info().IsInteger32()) return false; | 2360 if (result.number_info().IsInteger32()) return false; |
2358 if (!result.is_constant()) return true; | 2361 if (!result.is_constant()) return true; |
2359 if (!result.handle()->IsHeapNumber()) return false; | 2362 if (!result.handle()->IsHeapNumber()) return false; |
2360 return isnan(HeapNumber::cast(*result.handle())->value()); | 2363 return isnan(HeapNumber::cast(*result.handle())->value()); |
2361 } | 2364 } |
2362 | 2365 |
2363 | 2366 |
2367 // Convert from signed to unsigned comparison to match the way EFLAGS are set | |
2368 // by FPU and XMM compare instructions. | |
2369 static Condition DoubleCondition(Condition cc) { | |
2370 switch (cc) { | |
2371 case less: return below; | |
2372 case equal: return equal; | |
2373 case less_equal: return below_equal; | |
2374 case greater: return above; | |
2375 case greater_equal: return above_equal; | |
2376 default: UNREACHABLE(); | |
2377 } | |
2378 UNREACHABLE(); | |
2379 return equal; | |
2380 } | |
2381 | |
2382 | |
2364 void CodeGenerator::Comparison(AstNode* node, | 2383 void CodeGenerator::Comparison(AstNode* node, |
2365 Condition cc, | 2384 Condition cc, |
2366 bool strict, | 2385 bool strict, |
2367 ControlDestination* dest) { | 2386 ControlDestination* dest) { |
2368 // Strict only makes sense for equality comparisons. | 2387 // Strict only makes sense for equality comparisons. |
2369 ASSERT(!strict || cc == equal); | 2388 ASSERT(!strict || cc == equal); |
2370 | 2389 |
2371 Result left_side; | 2390 Result left_side; |
2372 Result right_side; | 2391 Result right_side; |
2373 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 2392 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2424 } | 2443 } |
2425 } else { | 2444 } else { |
2426 // Only one side is a constant Smi. | 2445 // Only one side is a constant Smi. |
2427 // If left side is a constant Smi, reverse the operands. | 2446 // If left side is a constant Smi, reverse the operands. |
2428 // Since one side is a constant Smi, conversion order does not matter. | 2447 // Since one side is a constant Smi, conversion order does not matter. |
2429 if (left_side_constant_smi) { | 2448 if (left_side_constant_smi) { |
2430 Result temp = left_side; | 2449 Result temp = left_side; |
2431 left_side = right_side; | 2450 left_side = right_side; |
2432 right_side = temp; | 2451 right_side = temp; |
2433 cc = ReverseCondition(cc); | 2452 cc = ReverseCondition(cc); |
2434 // This may reintroduce greater or less_equal as the value of cc. | 2453 // This may re-introduce greater or less_equal as the value of cc. |
2435 // CompareStub and the inline code both support all values of cc. | 2454 // CompareStub and the inline code both support all values of cc. |
2436 } | 2455 } |
2437 // Implement comparison against a constant Smi, inlining the case | 2456 // Implement comparison against a constant Smi, inlining the case |
2438 // where both sides are Smis. | 2457 // where both sides are Smis. |
2439 left_side.ToRegister(); | 2458 left_side.ToRegister(); |
2440 Register left_reg = left_side.reg(); | 2459 Register left_reg = left_side.reg(); |
2441 Handle<Object> right_val = right_side.handle(); | 2460 Handle<Object> right_val = right_side.handle(); |
2442 | 2461 |
2443 // Here we split control flow to the stub call and inlined cases | 2462 // Here we split control flow to the stub call and inlined cases |
2444 // before finally splitting it to the control destination. We use | 2463 // before finally splitting it to the control destination. We use |
(...skipping 28 matching lines...) Expand all Loading... | |
2473 } else { | 2492 } else { |
2474 Result temp = allocator()->Allocate(); | 2493 Result temp = allocator()->Allocate(); |
2475 __ mov(temp.reg(), Immediate(value)); | 2494 __ mov(temp.reg(), Immediate(value)); |
2476 __ cvtsi2sd(xmm0, Operand(temp.reg())); | 2495 __ cvtsi2sd(xmm0, Operand(temp.reg())); |
2477 temp.Unuse(); | 2496 temp.Unuse(); |
2478 } | 2497 } |
2479 __ comisd(xmm1, xmm0); | 2498 __ comisd(xmm1, xmm0); |
2480 // Jump to builtin for NaN. | 2499 // Jump to builtin for NaN. |
2481 not_number.Branch(parity_even, &left_side); | 2500 not_number.Branch(parity_even, &left_side); |
2482 left_side.Unuse(); | 2501 left_side.Unuse(); |
2483 Condition double_cc = cc; | 2502 dest->true_target()->Branch(DoubleCondition(cc)); |
2484 switch (cc) { | |
2485 case less: double_cc = below; break; | |
2486 case equal: double_cc = equal; break; | |
2487 case less_equal: double_cc = below_equal; break; | |
2488 case greater: double_cc = above; break; | |
2489 case greater_equal: double_cc = above_equal; break; | |
2490 default: UNREACHABLE(); | |
2491 } | |
2492 dest->true_target()->Branch(double_cc); | |
2493 dest->false_target()->Jump(); | 2503 dest->false_target()->Jump(); |
2494 not_number.Bind(&left_side); | 2504 not_number.Bind(&left_side); |
2495 } | 2505 } |
2496 | 2506 |
2497 // Setup and call the compare stub. | 2507 // Setup and call the compare stub. |
2498 CompareStub stub(cc, strict, kCantBothBeNaN); | 2508 CompareStub stub(cc, strict, kCantBothBeNaN); |
2499 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 2509 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
2500 result.ToRegister(); | 2510 result.ToRegister(); |
2501 __ cmp(result.reg(), 0); | 2511 __ cmp(result.reg(), 0); |
2502 result.Unuse(); | 2512 result.Unuse(); |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2681 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2691 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2682 Immediate(1)); | 2692 Immediate(1)); |
2683 __ bind(&characters_were_different); | 2693 __ bind(&characters_were_different); |
2684 } | 2694 } |
2685 temp2.Unuse(); | 2695 temp2.Unuse(); |
2686 left_side.Unuse(); | 2696 left_side.Unuse(); |
2687 right_side.Unuse(); | 2697 right_side.Unuse(); |
2688 dest->Split(cc); | 2698 dest->Split(cc); |
2689 } | 2699 } |
2690 } else { | 2700 } else { |
2691 // Neither side is a constant Smi or null. | 2701 // Neither side is a constant Smi, constant 1-char string or constant null. |
2692 // If either side is a non-smi constant, skip the smi check. | 2702 // If either side is a non-smi constant, or known to be a heap number skip |
2703 // the smi check. | |
2693 bool known_non_smi = | 2704 bool known_non_smi = |
2694 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 2705 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
2695 (right_side.is_constant() && !right_side.handle()->IsSmi()); | 2706 (right_side.is_constant() && !right_side.handle()->IsSmi()) || |
2707 left_side.number_info().IsHeapNumber() || | |
2708 right_side.number_info().IsHeapNumber(); | |
2696 NaNInformation nan_info = | 2709 NaNInformation nan_info = |
2697 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? | 2710 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? |
2698 kBothCouldBeNaN : | 2711 kBothCouldBeNaN : |
2699 kCantBothBeNaN; | 2712 kCantBothBeNaN; |
2713 | |
2714 // Inline number comparison handling any combination of smi's and heap | |
2715 // numbers if: | |
2716 // code is in a loop | |
2717 // the compare operation is different from equal | |
2718 // compare is not a for-loop comparison | |
2719 // The reason for excluding equal is that it will most likely be done | |
2720 // with smi's (not heap numbers) and the code to comparing smi's is inlined | |
2721 // separately. The same reason applies for for-loop comparison which will | |
2722 // also most likely be smi comparisons. | |
2723 bool is_for_loop_compare = (node->AsCompareOperation() != NULL) | |
2724 && node->AsCompareOperation()->is_for_loop_condition(); | |
2725 bool inline_number_compare = loop_nesting() > 0 | |
2726 && cc != equal | |
2727 && !is_for_loop_compare; | |
2728 | |
2729 // Left and right needed in registers for the following code. | |
2700 left_side.ToRegister(); | 2730 left_side.ToRegister(); |
2701 right_side.ToRegister(); | 2731 right_side.ToRegister(); |
2702 | 2732 |
2703 if (known_non_smi) { | 2733 if (known_non_smi) { |
2704 // When non-smi, call out to the compare stub. | 2734 // Inline the equality check if both operands can't be a NaN. If both |
2705 CompareStub stub(cc, strict, nan_info); | 2735 // objects are the same they are equal. |
2736 if (nan_info == kCantBothBeNaN && cc == equal) { | |
Erik Corry
2010/03/23 18:09:24
This seems wrong. If one side is a constant fp nu
Søren Thygesen Gjesse
2010/03/23 20:40:01
This will only provide true when the objects are t
| |
2737 __ cmp(left_side.reg(), Operand(right_side.reg())); | |
2738 dest->true_target()->Branch(equal); | |
2739 } | |
2740 | |
2741 // Inline number comparison. | |
2742 if (inline_number_compare) { | |
2743 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | |
2744 } | |
2745 | |
2746 // End of in-line compare, call out to the compare stub. Don't include | |
2747 // number comparison in the stub if it was inlined. | |
2748 CompareStub stub(cc, strict, nan_info, !inline_number_compare); | |
2706 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2749 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2707 if (cc == equal) { | 2750 if (cc == equal) { |
2708 __ test(answer.reg(), Operand(answer.reg())); | 2751 __ test(answer.reg(), Operand(answer.reg())); |
2709 } else { | 2752 } else { |
2710 __ cmp(answer.reg(), 0); | 2753 __ cmp(answer.reg(), 0); |
2711 } | 2754 } |
2712 answer.Unuse(); | 2755 answer.Unuse(); |
2713 dest->Split(cc); | 2756 dest->Split(cc); |
2714 } else { | 2757 } else { |
2715 // Here we split control flow to the stub call and inlined cases | 2758 // Here we split control flow to the stub call and inlined cases |
2716 // before finally splitting it to the control destination. We use | 2759 // before finally splitting it to the control destination. We use |
2717 // a jump target and branching to duplicate the virtual frame at | 2760 // a jump target and branching to duplicate the virtual frame at |
2718 // the first split. We manually handle the off-frame references | 2761 // the first split. We manually handle the off-frame references |
2719 // by reconstituting them on the non-fall-through path. | 2762 // by reconstituting them on the non-fall-through path. |
2720 JumpTarget is_smi; | 2763 JumpTarget is_smi; |
2721 Register left_reg = left_side.reg(); | 2764 Register left_reg = left_side.reg(); |
2722 Register right_reg = right_side.reg(); | 2765 Register right_reg = right_side.reg(); |
2723 | 2766 |
2767 // In-line check for comparing two smis. | |
2724 Result temp = allocator_->Allocate(); | 2768 Result temp = allocator_->Allocate(); |
2725 ASSERT(temp.is_valid()); | 2769 ASSERT(temp.is_valid()); |
2726 __ mov(temp.reg(), left_side.reg()); | 2770 __ mov(temp.reg(), left_side.reg()); |
2727 __ or_(temp.reg(), Operand(right_side.reg())); | 2771 __ or_(temp.reg(), Operand(right_side.reg())); |
2728 __ test(temp.reg(), Immediate(kSmiTagMask)); | 2772 __ test(temp.reg(), Immediate(kSmiTagMask)); |
2729 temp.Unuse(); | 2773 temp.Unuse(); |
2730 is_smi.Branch(zero, taken); | 2774 is_smi.Branch(zero, taken); |
2731 // When non-smi, call out to the compare stub. | 2775 |
2732 CompareStub stub(cc, strict, nan_info); | 2776 // Inline the equality check if both operands can't be a NaN. If both |
2777 // objects are the same they are equal. | |
2778 if (nan_info == kCantBothBeNaN && cc == equal) { | |
2779 __ cmp(left_side.reg(), Operand(right_side.reg())); | |
2780 dest->true_target()->Branch(equal); | |
2781 } | |
2782 | |
2783 // Inline number comparison. | |
2784 if (inline_number_compare) { | |
2785 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | |
2786 } | |
2787 | |
2788 // End of in-line compare, call out to the compare stub. Don't include | |
2789 // number comparison in the stub if it was inlined. | |
2790 CompareStub stub(cc, strict, nan_info, !inline_number_compare); | |
2733 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2791 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2734 if (cc == equal) { | 2792 if (cc == equal) { |
2735 __ test(answer.reg(), Operand(answer.reg())); | 2793 __ test(answer.reg(), Operand(answer.reg())); |
2736 } else { | 2794 } else { |
2737 __ cmp(answer.reg(), 0); | 2795 __ cmp(answer.reg(), 0); |
2738 } | 2796 } |
2739 answer.Unuse(); | 2797 answer.Unuse(); |
2740 dest->true_target()->Branch(cc); | 2798 dest->true_target()->Branch(cc); |
2741 dest->false_target()->Jump(); | 2799 dest->false_target()->Jump(); |
2742 | 2800 |
2743 is_smi.Bind(); | 2801 is_smi.Bind(); |
2744 left_side = Result(left_reg); | 2802 left_side = Result(left_reg); |
2745 right_side = Result(right_reg); | 2803 right_side = Result(right_reg); |
2746 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2804 __ cmp(left_side.reg(), Operand(right_side.reg())); |
2747 right_side.Unuse(); | 2805 right_side.Unuse(); |
2748 left_side.Unuse(); | 2806 left_side.Unuse(); |
2749 dest->Split(cc); | 2807 dest->Split(cc); |
2750 } | 2808 } |
2751 } | 2809 } |
2752 } | 2810 } |
2753 | 2811 |
2754 | 2812 |
2813 // Check that the comparison operand is a number. Jump to not_numbers jump | |
2814 // target passing the left and right result if the operand is not a number. | |
2815 static void CheckComparisonOperand(MacroAssembler* masm_, | |
2816 Result* operand, | |
2817 Result* left_side, | |
2818 Result* right_side, | |
2819 JumpTarget* not_numbers) { | |
2820 // Perform check if operand is not known to be a number. | |
2821 if (!operand->number_info().IsNumber()) { | |
2822 Label done; | |
2823 __ test(operand->reg(), Immediate(kSmiTagMask)); | |
2824 __ j(zero, &done); | |
2825 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), | |
2826 Immediate(Factory::heap_number_map())); | |
2827 not_numbers->Branch(not_equal, left_side, right_side, not_taken); | |
2828 __ bind(&done); | |
2829 } | |
2830 } | |
2831 | |
2832 | |
2833 // Load a comparison operand to the FPU stack. This assumes that the operand has | |
2834 // already been checked and is a number. | |
2835 static void LoadComparisonOperand(MacroAssembler* masm_, | |
2836 Result* operand, | |
2837 Result* left_side, | |
2838 Result* right_side) { | |
2839 Label done; | |
2840 if (operand->number_info().IsHeapNumber()) { | |
2841 // Operand is known to be a heap number, just load it. | |
2842 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2843 } else if (operand->number_info().IsSmi()) { | |
2844 // Operand is known to be a smi. Convert it to double and keep the original | |
2845 // smi. | |
2846 __ SmiUntag(operand->reg()); | |
2847 __ push(operand->reg()); | |
2848 __ fild_s(Operand(esp, 0)); | |
2849 __ pop(operand->reg()); | |
2850 __ SmiTag(operand->reg()); | |
2851 } else { | |
2852 // Operand type not known, check for smi otherwise assume heap number. | |
2853 Label smi; | |
2854 __ test(operand->reg(), Immediate(kSmiTagMask)); | |
2855 __ j(zero, &smi); | |
2856 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2857 __ jmp(&done); | |
2858 __ bind(&smi); | |
2859 __ SmiUntag(operand->reg()); | |
2860 __ push(operand->reg()); | |
2861 __ fild_s(Operand(esp, 0)); | |
2862 __ pop(operand->reg()); | |
2863 __ SmiTag(operand->reg()); | |
2864 __ jmp(&done); | |
2865 } | |
2866 __ bind(&done); | |
2867 } | |
2868 | |
2869 | |
2870 // Load a comparison operand into into a XMM register. Jump to not_numbers jump | |
2871 // target passing the left and right result if the operand is not a number. | |
2872 static void LoadComparisonOperandSSE2(MacroAssembler* masm_, | |
2873 Result* operand, | |
2874 XMMRegister reg, | |
2875 Result* left_side, | |
2876 Result* right_side, | |
2877 JumpTarget* not_numbers) { | |
2878 Label done; | |
2879 if (operand->number_info().IsHeapNumber()) { | |
2880 // Operand is known to be a heap number, just load it. | |
2881 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2882 } else if (operand->number_info().IsSmi()) { | |
2883 // Operand is known to be a smi. Convert it to double and keep the original | |
2884 // smi. | |
2885 __ SmiUntag(operand->reg()); | |
2886 __ cvtsi2sd(reg, Operand(operand->reg())); | |
2887 __ SmiTag(left_side->reg()); | |
2888 } else { | |
2889 // Operand type not known, check for smi or heap number. | |
2890 Label smi; | |
2891 __ test(operand->reg(), Immediate(kSmiTagMask)); | |
2892 __ j(zero, &smi); | |
2893 if (!operand->number_info().IsNumber()) { | |
2894 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), | |
2895 Immediate(Factory::heap_number_map())); | |
2896 not_numbers->Branch(not_equal, left_side, right_side, taken); | |
2897 } | |
2898 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2899 __ jmp(&done); | |
2900 | |
2901 __ bind(&smi); | |
2902 // Comvert smi to float and keep the original smi. | |
2903 __ SmiUntag(operand->reg()); | |
2904 __ cvtsi2sd(reg, Operand(operand->reg())); | |
2905 __ SmiTag(operand->reg()); | |
2906 __ jmp(&done); | |
2907 } | |
2908 __ bind(&done); | |
2909 } | |
2910 | |
2911 | |
2912 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, | |
2913 Result* right_side, | |
2914 Condition cc, | |
2915 ControlDestination* dest) { | |
2916 ASSERT(left_side->is_register()); | |
2917 ASSERT(right_side->is_register()); | |
2918 | |
2919 JumpTarget not_numbers; | |
2920 if (CpuFeatures::IsSupported(SSE2)) { | |
2921 CpuFeatures::Scope use_sse2(SSE2); | |
2922 | |
2923 // Load left and right operand into registers xmm0 and xmm1 and compare. | |
2924 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, | |
2925 ¬_numbers); | |
2926 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, | |
2927 ¬_numbers); | |
2928 __ comisd(xmm0, xmm1); | |
2929 } else { | |
2930 Label check_right, compare; | |
2931 | |
2932 // Make sure that both comparison operands are numbers. | |
2933 CheckComparisonOperand(masm_, left_side, left_side, right_side, | |
2934 ¬_numbers); | |
2935 CheckComparisonOperand(masm_, right_side, left_side, right_side, | |
2936 ¬_numbers); | |
2937 | |
2938 // Load right and left operand to FPU stack and compare. | |
2939 LoadComparisonOperand(masm_, right_side, left_side, right_side); | |
2940 LoadComparisonOperand(masm_, left_side, left_side, right_side); | |
2941 __ FCmp(); | |
2942 } | |
2943 | |
2944 // Bail out if a NaN is involved. | |
2945 not_numbers.Branch(parity_even, left_side, right_side, not_taken); | |
2946 | |
2947 // Split to destination targets based on comparison. | |
2948 left_side->Unuse(); | |
2949 right_side->Unuse(); | |
2950 dest->true_target()->Branch(DoubleCondition(cc)); | |
2951 dest->false_target()->Jump(); | |
2952 | |
2953 not_numbers.Bind(left_side, right_side); | |
2954 } | |
2955 | |
2956 | |
2755 // Call the function just below TOS on the stack with the given | 2957 // Call the function just below TOS on the stack with the given |
2756 // arguments. The receiver is the TOS. | 2958 // arguments. The receiver is the TOS. |
2757 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 2959 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
2758 CallFunctionFlags flags, | 2960 CallFunctionFlags flags, |
2759 int position) { | 2961 int position) { |
2760 // Push the arguments ("left-to-right") on the stack. | 2962 // Push the arguments ("left-to-right") on the stack. |
2761 int arg_count = args->length(); | 2963 int arg_count = args->length(); |
2762 for (int i = 0; i < arg_count; i++) { | 2964 for (int i = 0; i < arg_count; i++) { |
2763 Load(args->at(i)); | 2965 Load(args->at(i)); |
2764 } | 2966 } |
(...skipping 8049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10814 } | 11016 } |
10815 __ bind(&slow); | 11017 __ bind(&slow); |
10816 } | 11018 } |
10817 | 11019 |
10818 // Push arguments below the return address. | 11020 // Push arguments below the return address. |
10819 __ pop(ecx); | 11021 __ pop(ecx); |
10820 __ push(eax); | 11022 __ push(eax); |
10821 __ push(edx); | 11023 __ push(edx); |
10822 __ push(ecx); | 11024 __ push(ecx); |
10823 | 11025 |
10824 // Inlined floating point compare. | 11026 // Generate the number comparison code. |
10825 // Call builtin if operands are not floating point or smi. | 11027 if (include_number_compare_) { |
10826 Label check_for_symbols; | 11028 Label non_number_comparison; |
10827 Label unordered; | 11029 Label unordered; |
10828 if (CpuFeatures::IsSupported(SSE2)) { | 11030 if (CpuFeatures::IsSupported(SSE2)) { |
10829 CpuFeatures::Scope use_sse2(SSE2); | 11031 CpuFeatures::Scope use_sse2(SSE2); |
10830 CpuFeatures::Scope use_cmov(CMOV); | 11032 CpuFeatures::Scope use_cmov(CMOV); |
10831 | 11033 |
10832 FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols); | 11034 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); |
10833 __ comisd(xmm0, xmm1); | 11035 __ comisd(xmm0, xmm1); |
10834 | 11036 |
10835 // Jump to builtin for NaN. | 11037 // Don't base result on EFLAGS when a NaN is involved. |
10836 __ j(parity_even, &unordered, not_taken); | 11038 __ j(parity_even, &unordered, not_taken); |
10837 __ mov(eax, 0); // equal | 11039 // Return a result of -1, 0, or 1, based on EFLAGS. |
10838 __ mov(ecx, Immediate(Smi::FromInt(1))); | 11040 __ mov(eax, 0); // equal |
10839 __ cmov(above, eax, Operand(ecx)); | 11041 __ mov(ecx, Immediate(Smi::FromInt(1))); |
10840 __ mov(ecx, Immediate(Smi::FromInt(-1))); | 11042 __ cmov(above, eax, Operand(ecx)); |
10841 __ cmov(below, eax, Operand(ecx)); | 11043 __ mov(ecx, Immediate(Smi::FromInt(-1))); |
10842 __ ret(2 * kPointerSize); | 11044 __ cmov(below, eax, Operand(ecx)); |
10843 } else { | 11045 __ ret(2 * kPointerSize); |
10844 FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); | 11046 } else { |
10845 FloatingPointHelper::LoadFloatOperands(masm, ecx); | 11047 FloatingPointHelper::CheckFloatOperands( |
10846 __ FCmp(); | 11048 masm, &non_number_comparison, ebx); |
11049 FloatingPointHelper::LoadFloatOperands(masm, ecx); | |
11050 __ FCmp(); | |
10847 | 11051 |
10848 // Jump to builtin for NaN. | 11052 // Don't base result on EFLAGS when a NaN is involved. |
10849 __ j(parity_even, &unordered, not_taken); | 11053 __ j(parity_even, &unordered, not_taken); |
10850 | 11054 |
10851 Label below_lbl, above_lbl; | 11055 Label below_label, above_label; |
10852 // Return a result of -1, 0, or 1, to indicate result of comparison. | 11056 // Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove |
10853 __ j(below, &below_lbl, not_taken); | 11057 // two arguments from the stack as they have been pushed in preparation |
10854 __ j(above, &above_lbl, not_taken); | 11058 // of a possible runtime call. |
11059 __ j(below, &below_label, not_taken); | |
11060 __ j(above, &above_label, not_taken); | |
10855 | 11061 |
10856 __ xor_(eax, Operand(eax)); // equal | 11062 __ xor_(eax, Operand(eax)); |
10857 // Both arguments were pushed in case a runtime call was needed. | 11063 __ ret(2 * kPointerSize); |
10858 __ ret(2 * kPointerSize); | |
10859 | 11064 |
10860 __ bind(&below_lbl); | 11065 __ bind(&below_label); |
10861 __ mov(eax, Immediate(Smi::FromInt(-1))); | 11066 __ mov(eax, Immediate(Smi::FromInt(-1))); |
10862 __ ret(2 * kPointerSize); | 11067 __ ret(2 * kPointerSize); |
10863 | 11068 |
10864 __ bind(&above_lbl); | 11069 __ bind(&above_label); |
10865 __ mov(eax, Immediate(Smi::FromInt(1))); | 11070 __ mov(eax, Immediate(Smi::FromInt(1))); |
11071 __ ret(2 * kPointerSize); | |
11072 } | |
11073 | |
11074 // If one of the numbers was NaN, then the result is always false. | |
11075 // The cc is never not-equal. | |
11076 __ bind(&unordered); | |
11077 ASSERT(cc_ != not_equal); | |
11078 if (cc_ == less || cc_ == less_equal) { | |
11079 __ mov(eax, Immediate(Smi::FromInt(1))); | |
11080 } else { | |
11081 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
11082 } | |
10866 __ ret(2 * kPointerSize); // eax, edx were pushed | 11083 __ ret(2 * kPointerSize); // eax, edx were pushed |
11084 | |
11085 // The number comparison code did not provide a valid result. | |
11086 __ bind(&non_number_comparison); | |
10867 } | 11087 } |
10868 // If one of the numbers was NaN, then the result is always false. | |
10869 // The cc is never not-equal. | |
10870 __ bind(&unordered); | |
10871 ASSERT(cc_ != not_equal); | |
10872 if (cc_ == less || cc_ == less_equal) { | |
10873 __ mov(eax, Immediate(Smi::FromInt(1))); | |
10874 } else { | |
10875 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
10876 } | |
10877 __ ret(2 * kPointerSize); // eax, edx were pushed | |
10878 | 11088 |
10879 // Fast negative check for symbol-to-symbol equality. | 11089 // Fast negative check for symbol-to-symbol equality. |
10880 __ bind(&check_for_symbols); | |
10881 Label check_for_strings; | 11090 Label check_for_strings; |
10882 if (cc_ == equal) { | 11091 if (cc_ == equal) { |
10883 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); | 11092 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); |
10884 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); | 11093 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
10885 | 11094 |
10886 // We've already checked for object identity, so if both operands | 11095 // We've already checked for object identity, so if both operands |
10887 // are symbols they aren't equal. Register eax already holds a | 11096 // are symbols they aren't equal. Register eax already holds a |
10888 // non-zero value, which indicates not equal, so just return. | 11097 // non-zero value, which indicates not equal, so just return. |
10889 __ ret(2 * kPointerSize); | 11098 __ ret(2 * kPointerSize); |
10890 } | 11099 } |
(...skipping 636 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11527 } | 11736 } |
11528 default: return "CompareStub"; | 11737 default: return "CompareStub"; |
11529 } | 11738 } |
11530 } | 11739 } |
11531 | 11740 |
11532 | 11741 |
11533 int CompareStub::MinorKey() { | 11742 int CompareStub::MinorKey() { |
11534 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | 11743 // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
11535 // stubs the never NaN NaN condition is only taken into account if the | 11744 // stubs the never NaN NaN condition is only taken into account if the |
11536 // condition is equals. | 11745 // condition is equals. |
11537 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); | 11746 ASSERT(static_cast<unsigned>(cc_) < (1 << 13)); |
11538 return ConditionField::encode(static_cast<unsigned>(cc_)) | 11747 return ConditionField::encode(static_cast<unsigned>(cc_)) |
11539 | StrictField::encode(strict_) | 11748 | StrictField::encode(strict_) |
11540 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false); | 11749 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) |
11750 | IncludeNumberCompareField::encode(include_number_compare_); | |
11541 } | 11751 } |
11542 | 11752 |
11543 | 11753 |
11544 void StringAddStub::Generate(MacroAssembler* masm) { | 11754 void StringAddStub::Generate(MacroAssembler* masm) { |
11545 Label string_add_runtime; | 11755 Label string_add_runtime; |
11546 | 11756 |
11547 // Load the two arguments. | 11757 // Load the two arguments. |
11548 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 11758 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
11549 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 11759 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
11550 | 11760 |
(...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12164 | 12374 |
12165 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 12375 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
12166 Register left, | 12376 Register left, |
12167 Register right, | 12377 Register right, |
12168 Register scratch1, | 12378 Register scratch1, |
12169 Register scratch2, | 12379 Register scratch2, |
12170 Register scratch3) { | 12380 Register scratch3) { |
12171 Label result_not_equal; | 12381 Label result_not_equal; |
12172 Label result_greater; | 12382 Label result_greater; |
12173 Label compare_lengths; | 12383 Label compare_lengths; |
12384 | |
12385 __ IncrementCounter(&Counters::string_compare_native, 1); | |
12386 | |
12174 // Find minimum length. | 12387 // Find minimum length. |
12175 Label left_shorter; | 12388 Label left_shorter; |
12176 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 12389 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
12177 __ mov(scratch3, scratch1); | 12390 __ mov(scratch3, scratch1); |
12178 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); | 12391 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
12179 | 12392 |
12180 Register length_delta = scratch3; | 12393 Register length_delta = scratch3; |
12181 | 12394 |
12182 __ j(less_equal, &left_shorter); | 12395 __ j(less_equal, &left_shorter); |
12183 // Right string is shorter. Change scratch1 to be length of right string. | 12396 // Right string is shorter. Change scratch1 to be length of right string. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12261 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 12474 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
12262 __ IncrementCounter(&Counters::string_compare_native, 1); | 12475 __ IncrementCounter(&Counters::string_compare_native, 1); |
12263 __ ret(2 * kPointerSize); | 12476 __ ret(2 * kPointerSize); |
12264 | 12477 |
12265 __ bind(¬_same); | 12478 __ bind(¬_same); |
12266 | 12479 |
12267 // Check that both objects are sequential ascii strings. | 12480 // Check that both objects are sequential ascii strings. |
12268 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 12481 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
12269 | 12482 |
12270 // Compare flat ascii strings. | 12483 // Compare flat ascii strings. |
12271 __ IncrementCounter(&Counters::string_compare_native, 1); | |
12272 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 12484 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
12273 | 12485 |
12274 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12486 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
12275 // tagged as a small integer. | 12487 // tagged as a small integer. |
12276 __ bind(&runtime); | 12488 __ bind(&runtime); |
12277 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12489 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
12278 } | 12490 } |
12279 | 12491 |
12280 #undef __ | 12492 #undef __ |
12281 | 12493 |
12282 } } // namespace v8::internal | 12494 } } // namespace v8::internal |
OLD | NEW |