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().IsDouble() || |
| 2708 right_side.number_info().IsDouble(); |
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_loop_condition = (node->AsExpression() != NULL) |
| 2724 && node->AsExpression()->is_loop_condition(); |
| 2725 bool inline_number_compare = |
| 2726 loop_nesting() > 0 && cc != equal && !is_loop_condition; |
| 2727 |
| 2728 // Left and right needed in registers for the following code. |
2700 left_side.ToRegister(); | 2729 left_side.ToRegister(); |
2701 right_side.ToRegister(); | 2730 right_side.ToRegister(); |
2702 | 2731 |
2703 if (known_non_smi) { | 2732 if (known_non_smi) { |
2704 // When non-smi, call out to the compare stub. | 2733 // Inline the equality check if both operands can't be a NaN. If both |
2705 CompareStub stub(cc, strict, nan_info); | 2734 // objects are the same they are equal. |
| 2735 if (nan_info == kCantBothBeNaN && cc == equal) { |
| 2736 __ cmp(left_side.reg(), Operand(right_side.reg())); |
| 2737 dest->true_target()->Branch(equal); |
| 2738 } |
| 2739 |
| 2740 // Inline number comparison. |
| 2741 if (inline_number_compare) { |
| 2742 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
| 2743 } |
| 2744 |
| 2745 // End of in-line compare, call out to the compare stub. Don't include |
| 2746 // number comparison in the stub if it was inlined. |
| 2747 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
2706 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2748 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2707 if (cc == equal) { | 2749 if (cc == equal) { |
2708 __ test(answer.reg(), Operand(answer.reg())); | 2750 __ test(answer.reg(), Operand(answer.reg())); |
2709 } else { | 2751 } else { |
2710 __ cmp(answer.reg(), 0); | 2752 __ cmp(answer.reg(), 0); |
2711 } | 2753 } |
2712 answer.Unuse(); | 2754 answer.Unuse(); |
2713 dest->Split(cc); | 2755 dest->Split(cc); |
2714 } else { | 2756 } else { |
2715 // Here we split control flow to the stub call and inlined cases | 2757 // Here we split control flow to the stub call and inlined cases |
2716 // before finally splitting it to the control destination. We use | 2758 // before finally splitting it to the control destination. We use |
2717 // a jump target and branching to duplicate the virtual frame at | 2759 // a jump target and branching to duplicate the virtual frame at |
2718 // the first split. We manually handle the off-frame references | 2760 // the first split. We manually handle the off-frame references |
2719 // by reconstituting them on the non-fall-through path. | 2761 // by reconstituting them on the non-fall-through path. |
2720 JumpTarget is_smi; | 2762 JumpTarget is_smi; |
2721 Register left_reg = left_side.reg(); | 2763 Register left_reg = left_side.reg(); |
2722 Register right_reg = right_side.reg(); | 2764 Register right_reg = right_side.reg(); |
2723 | 2765 |
| 2766 // In-line check for comparing two smis. |
2724 Result temp = allocator_->Allocate(); | 2767 Result temp = allocator_->Allocate(); |
2725 ASSERT(temp.is_valid()); | 2768 ASSERT(temp.is_valid()); |
2726 __ mov(temp.reg(), left_side.reg()); | 2769 __ mov(temp.reg(), left_side.reg()); |
2727 __ or_(temp.reg(), Operand(right_side.reg())); | 2770 __ or_(temp.reg(), Operand(right_side.reg())); |
2728 __ test(temp.reg(), Immediate(kSmiTagMask)); | 2771 __ test(temp.reg(), Immediate(kSmiTagMask)); |
2729 temp.Unuse(); | 2772 temp.Unuse(); |
2730 is_smi.Branch(zero, taken); | 2773 is_smi.Branch(zero, taken); |
2731 // When non-smi, call out to the compare stub. | 2774 |
2732 CompareStub stub(cc, strict, nan_info); | 2775 // Inline the equality check if both operands can't be a NaN. If both |
| 2776 // objects are the same they are equal. |
| 2777 if (nan_info == kCantBothBeNaN && cc == equal) { |
| 2778 __ cmp(left_side.reg(), Operand(right_side.reg())); |
| 2779 dest->true_target()->Branch(equal); |
| 2780 } |
| 2781 |
| 2782 // Inline number comparison. |
| 2783 if (inline_number_compare) { |
| 2784 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
| 2785 } |
| 2786 |
| 2787 // End of in-line compare, call out to the compare stub. Don't include |
| 2788 // number comparison in the stub if it was inlined. |
| 2789 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
2733 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2790 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2734 if (cc == equal) { | 2791 if (cc == equal) { |
2735 __ test(answer.reg(), Operand(answer.reg())); | 2792 __ test(answer.reg(), Operand(answer.reg())); |
2736 } else { | 2793 } else { |
2737 __ cmp(answer.reg(), 0); | 2794 __ cmp(answer.reg(), 0); |
2738 } | 2795 } |
2739 answer.Unuse(); | 2796 answer.Unuse(); |
2740 dest->true_target()->Branch(cc); | 2797 dest->true_target()->Branch(cc); |
2741 dest->false_target()->Jump(); | 2798 dest->false_target()->Jump(); |
2742 | 2799 |
2743 is_smi.Bind(); | 2800 is_smi.Bind(); |
2744 left_side = Result(left_reg); | 2801 left_side = Result(left_reg); |
2745 right_side = Result(right_reg); | 2802 right_side = Result(right_reg); |
2746 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2803 __ cmp(left_side.reg(), Operand(right_side.reg())); |
2747 right_side.Unuse(); | 2804 right_side.Unuse(); |
2748 left_side.Unuse(); | 2805 left_side.Unuse(); |
2749 dest->Split(cc); | 2806 dest->Split(cc); |
2750 } | 2807 } |
2751 } | 2808 } |
2752 } | 2809 } |
2753 | 2810 |
2754 | 2811 |
| 2812 // Check that the comparison operand is a number. Jump to not_numbers jump |
| 2813 // target passing the left and right result if the operand is not a number. |
| 2814 static void CheckComparisonOperand(MacroAssembler* masm_, |
| 2815 Result* operand, |
| 2816 Result* left_side, |
| 2817 Result* right_side, |
| 2818 JumpTarget* not_numbers) { |
| 2819 // Perform check if operand is not known to be a number. |
| 2820 if (!operand->number_info().IsNumber()) { |
| 2821 Label done; |
| 2822 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2823 __ j(zero, &done); |
| 2824 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), |
| 2825 Immediate(Factory::heap_number_map())); |
| 2826 not_numbers->Branch(not_equal, left_side, right_side, not_taken); |
| 2827 __ bind(&done); |
| 2828 } |
| 2829 } |
| 2830 |
| 2831 |
| 2832 // Load a comparison operand to the FPU stack. This assumes that the operand has |
| 2833 // already been checked and is a number. |
| 2834 static void LoadComparisonOperand(MacroAssembler* masm_, |
| 2835 Result* operand) { |
| 2836 Label done; |
| 2837 if (operand->number_info().IsDouble()) { |
| 2838 // Operand is known to be a heap number, just load it. |
| 2839 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 2840 } else if (operand->number_info().IsSmi()) { |
| 2841 // Operand is known to be a smi. Convert it to double and keep the original |
| 2842 // smi. |
| 2843 __ SmiUntag(operand->reg()); |
| 2844 __ push(operand->reg()); |
| 2845 __ fild_s(Operand(esp, 0)); |
| 2846 __ pop(operand->reg()); |
| 2847 __ SmiTag(operand->reg()); |
| 2848 } else { |
| 2849 // Operand type not known, check for smi otherwise assume heap number. |
| 2850 Label smi; |
| 2851 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2852 __ j(zero, &smi); |
| 2853 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 2854 __ jmp(&done); |
| 2855 __ bind(&smi); |
| 2856 __ SmiUntag(operand->reg()); |
| 2857 __ push(operand->reg()); |
| 2858 __ fild_s(Operand(esp, 0)); |
| 2859 __ pop(operand->reg()); |
| 2860 __ SmiTag(operand->reg()); |
| 2861 __ jmp(&done); |
| 2862 } |
| 2863 __ bind(&done); |
| 2864 } |
| 2865 |
| 2866 |
| 2867 // Load a comparison operand into into a XMM register. Jump to not_numbers jump |
| 2868 // target passing the left and right result if the operand is not a number. |
| 2869 static void LoadComparisonOperandSSE2(MacroAssembler* masm_, |
| 2870 Result* operand, |
| 2871 XMMRegister reg, |
| 2872 Result* left_side, |
| 2873 Result* right_side, |
| 2874 JumpTarget* not_numbers) { |
| 2875 Label done; |
| 2876 if (operand->number_info().IsDouble()) { |
| 2877 // Operand is known to be a heap number, just load it. |
| 2878 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 2879 } else if (operand->number_info().IsSmi()) { |
| 2880 // Operand is known to be a smi. Convert it to double and keep the original |
| 2881 // smi. |
| 2882 __ SmiUntag(operand->reg()); |
| 2883 __ cvtsi2sd(reg, Operand(operand->reg())); |
| 2884 __ SmiTag(operand->reg()); |
| 2885 } else { |
| 2886 // Operand type not known, check for smi or heap number. |
| 2887 Label smi; |
| 2888 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2889 __ j(zero, &smi); |
| 2890 if (!operand->number_info().IsNumber()) { |
| 2891 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), |
| 2892 Immediate(Factory::heap_number_map())); |
| 2893 not_numbers->Branch(not_equal, left_side, right_side, taken); |
| 2894 } |
| 2895 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
| 2896 __ jmp(&done); |
| 2897 |
| 2898 __ bind(&smi); |
| 2899 // Comvert smi to float and keep the original smi. |
| 2900 __ SmiUntag(operand->reg()); |
| 2901 __ cvtsi2sd(reg, Operand(operand->reg())); |
| 2902 __ SmiTag(operand->reg()); |
| 2903 __ jmp(&done); |
| 2904 } |
| 2905 __ bind(&done); |
| 2906 } |
| 2907 |
| 2908 |
| 2909 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, |
| 2910 Result* right_side, |
| 2911 Condition cc, |
| 2912 ControlDestination* dest) { |
| 2913 ASSERT(left_side->is_register()); |
| 2914 ASSERT(right_side->is_register()); |
| 2915 |
| 2916 JumpTarget not_numbers; |
| 2917 if (CpuFeatures::IsSupported(SSE2)) { |
| 2918 CpuFeatures::Scope use_sse2(SSE2); |
| 2919 |
| 2920 // Load left and right operand into registers xmm0 and xmm1 and compare. |
| 2921 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, |
| 2922 ¬_numbers); |
| 2923 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, |
| 2924 ¬_numbers); |
| 2925 __ comisd(xmm0, xmm1); |
| 2926 } else { |
| 2927 Label check_right, compare; |
| 2928 |
| 2929 // Make sure that both comparison operands are numbers. |
| 2930 CheckComparisonOperand(masm_, left_side, left_side, right_side, |
| 2931 ¬_numbers); |
| 2932 CheckComparisonOperand(masm_, right_side, left_side, right_side, |
| 2933 ¬_numbers); |
| 2934 |
| 2935 // Load right and left operand to FPU stack and compare. |
| 2936 LoadComparisonOperand(masm_, right_side); |
| 2937 LoadComparisonOperand(masm_, left_side); |
| 2938 __ FCmp(); |
| 2939 } |
| 2940 |
| 2941 // Bail out if a NaN is involved. |
| 2942 not_numbers.Branch(parity_even, left_side, right_side, not_taken); |
| 2943 |
| 2944 // Split to destination targets based on comparison. |
| 2945 left_side->Unuse(); |
| 2946 right_side->Unuse(); |
| 2947 dest->true_target()->Branch(DoubleCondition(cc)); |
| 2948 dest->false_target()->Jump(); |
| 2949 |
| 2950 not_numbers.Bind(left_side, right_side); |
| 2951 } |
| 2952 |
| 2953 |
2755 // Call the function just below TOS on the stack with the given | 2954 // Call the function just below TOS on the stack with the given |
2756 // arguments. The receiver is the TOS. | 2955 // arguments. The receiver is the TOS. |
2757 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 2956 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
2758 CallFunctionFlags flags, | 2957 CallFunctionFlags flags, |
2759 int position) { | 2958 int position) { |
2760 // Push the arguments ("left-to-right") on the stack. | 2959 // Push the arguments ("left-to-right") on the stack. |
2761 int arg_count = args->length(); | 2960 int arg_count = args->length(); |
2762 for (int i = 0; i < arg_count; i++) { | 2961 for (int i = 0; i < arg_count; i++) { |
2763 Load(args->at(i)); | 2962 Load(args->at(i)); |
2764 } | 2963 } |
(...skipping 8105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10870 } | 11069 } |
10871 __ bind(&slow); | 11070 __ bind(&slow); |
10872 } | 11071 } |
10873 | 11072 |
10874 // Push arguments below the return address. | 11073 // Push arguments below the return address. |
10875 __ pop(ecx); | 11074 __ pop(ecx); |
10876 __ push(eax); | 11075 __ push(eax); |
10877 __ push(edx); | 11076 __ push(edx); |
10878 __ push(ecx); | 11077 __ push(ecx); |
10879 | 11078 |
10880 // Inlined floating point compare. | 11079 // Generate the number comparison code. |
10881 // Call builtin if operands are not floating point or smi. | 11080 if (include_number_compare_) { |
10882 Label check_for_symbols; | 11081 Label non_number_comparison; |
10883 Label unordered; | 11082 Label unordered; |
10884 if (CpuFeatures::IsSupported(SSE2)) { | 11083 if (CpuFeatures::IsSupported(SSE2)) { |
10885 CpuFeatures::Scope use_sse2(SSE2); | 11084 CpuFeatures::Scope use_sse2(SSE2); |
10886 CpuFeatures::Scope use_cmov(CMOV); | 11085 CpuFeatures::Scope use_cmov(CMOV); |
10887 | 11086 |
10888 FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols); | 11087 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); |
10889 __ comisd(xmm0, xmm1); | 11088 __ comisd(xmm0, xmm1); |
10890 | 11089 |
10891 // Jump to builtin for NaN. | 11090 // Don't base result on EFLAGS when a NaN is involved. |
10892 __ j(parity_even, &unordered, not_taken); | 11091 __ j(parity_even, &unordered, not_taken); |
10893 __ mov(eax, 0); // equal | 11092 // Return a result of -1, 0, or 1, based on EFLAGS. |
10894 __ mov(ecx, Immediate(Smi::FromInt(1))); | 11093 __ mov(eax, 0); // equal |
10895 __ cmov(above, eax, Operand(ecx)); | 11094 __ mov(ecx, Immediate(Smi::FromInt(1))); |
10896 __ mov(ecx, Immediate(Smi::FromInt(-1))); | 11095 __ cmov(above, eax, Operand(ecx)); |
10897 __ cmov(below, eax, Operand(ecx)); | 11096 __ mov(ecx, Immediate(Smi::FromInt(-1))); |
10898 __ ret(2 * kPointerSize); | 11097 __ cmov(below, eax, Operand(ecx)); |
10899 } else { | 11098 __ ret(2 * kPointerSize); |
10900 FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); | 11099 } else { |
10901 FloatingPointHelper::LoadFloatOperands(masm, ecx); | 11100 FloatingPointHelper::CheckFloatOperands( |
10902 __ FCmp(); | 11101 masm, &non_number_comparison, ebx); |
| 11102 FloatingPointHelper::LoadFloatOperands(masm, ecx); |
| 11103 __ FCmp(); |
10903 | 11104 |
10904 // Jump to builtin for NaN. | 11105 // Don't base result on EFLAGS when a NaN is involved. |
10905 __ j(parity_even, &unordered, not_taken); | 11106 __ j(parity_even, &unordered, not_taken); |
10906 | 11107 |
10907 Label below_lbl, above_lbl; | 11108 Label below_label, above_label; |
10908 // Return a result of -1, 0, or 1, to indicate result of comparison. | 11109 // Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove |
10909 __ j(below, &below_lbl, not_taken); | 11110 // two arguments from the stack as they have been pushed in preparation |
10910 __ j(above, &above_lbl, not_taken); | 11111 // of a possible runtime call. |
| 11112 __ j(below, &below_label, not_taken); |
| 11113 __ j(above, &above_label, not_taken); |
10911 | 11114 |
10912 __ xor_(eax, Operand(eax)); // equal | 11115 __ xor_(eax, Operand(eax)); |
10913 // Both arguments were pushed in case a runtime call was needed. | 11116 __ ret(2 * kPointerSize); |
10914 __ ret(2 * kPointerSize); | |
10915 | 11117 |
10916 __ bind(&below_lbl); | 11118 __ bind(&below_label); |
10917 __ mov(eax, Immediate(Smi::FromInt(-1))); | 11119 __ mov(eax, Immediate(Smi::FromInt(-1))); |
10918 __ ret(2 * kPointerSize); | 11120 __ ret(2 * kPointerSize); |
10919 | 11121 |
10920 __ bind(&above_lbl); | 11122 __ bind(&above_label); |
10921 __ mov(eax, Immediate(Smi::FromInt(1))); | 11123 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 11124 __ ret(2 * kPointerSize); |
| 11125 } |
| 11126 |
| 11127 // If one of the numbers was NaN, then the result is always false. |
| 11128 // The cc is never not-equal. |
| 11129 __ bind(&unordered); |
| 11130 ASSERT(cc_ != not_equal); |
| 11131 if (cc_ == less || cc_ == less_equal) { |
| 11132 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 11133 } else { |
| 11134 __ mov(eax, Immediate(Smi::FromInt(-1))); |
| 11135 } |
10922 __ ret(2 * kPointerSize); // eax, edx were pushed | 11136 __ ret(2 * kPointerSize); // eax, edx were pushed |
| 11137 |
| 11138 // The number comparison code did not provide a valid result. |
| 11139 __ bind(&non_number_comparison); |
10923 } | 11140 } |
10924 // If one of the numbers was NaN, then the result is always false. | |
10925 // The cc is never not-equal. | |
10926 __ bind(&unordered); | |
10927 ASSERT(cc_ != not_equal); | |
10928 if (cc_ == less || cc_ == less_equal) { | |
10929 __ mov(eax, Immediate(Smi::FromInt(1))); | |
10930 } else { | |
10931 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
10932 } | |
10933 __ ret(2 * kPointerSize); // eax, edx were pushed | |
10934 | 11141 |
10935 // Fast negative check for symbol-to-symbol equality. | 11142 // Fast negative check for symbol-to-symbol equality. |
10936 __ bind(&check_for_symbols); | |
10937 Label check_for_strings; | 11143 Label check_for_strings; |
10938 if (cc_ == equal) { | 11144 if (cc_ == equal) { |
10939 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); | 11145 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); |
10940 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); | 11146 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
10941 | 11147 |
10942 // We've already checked for object identity, so if both operands | 11148 // We've already checked for object identity, so if both operands |
10943 // are symbols they aren't equal. Register eax already holds a | 11149 // are symbols they aren't equal. Register eax already holds a |
10944 // non-zero value, which indicates not equal, so just return. | 11150 // non-zero value, which indicates not equal, so just return. |
10945 __ ret(2 * kPointerSize); | 11151 __ ret(2 * kPointerSize); |
10946 } | 11152 } |
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11536 __ bind(&is_not_instance); | 11742 __ bind(&is_not_instance); |
11537 __ Set(eax, Immediate(Smi::FromInt(1))); | 11743 __ Set(eax, Immediate(Smi::FromInt(1))); |
11538 __ ret(2 * kPointerSize); | 11744 __ ret(2 * kPointerSize); |
11539 | 11745 |
11540 // Slow-case: Go through the JavaScript implementation. | 11746 // Slow-case: Go through the JavaScript implementation. |
11541 __ bind(&slow); | 11747 __ bind(&slow); |
11542 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 11748 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
11543 } | 11749 } |
11544 | 11750 |
11545 | 11751 |
11546 // Unfortunately you have to run without snapshots to see most of these | |
11547 // names in the profile since most compare stubs end up in the snapshot. | |
11548 const char* CompareStub::GetName() { | |
11549 switch (cc_) { | |
11550 case less: return "CompareStub_LT"; | |
11551 case greater: return "CompareStub_GT"; | |
11552 case less_equal: return "CompareStub_LE"; | |
11553 case greater_equal: return "CompareStub_GE"; | |
11554 case not_equal: { | |
11555 if (strict_) { | |
11556 if (never_nan_nan_) { | |
11557 return "CompareStub_NE_STRICT_NO_NAN"; | |
11558 } else { | |
11559 return "CompareStub_NE_STRICT"; | |
11560 } | |
11561 } else { | |
11562 if (never_nan_nan_) { | |
11563 return "CompareStub_NE_NO_NAN"; | |
11564 } else { | |
11565 return "CompareStub_NE"; | |
11566 } | |
11567 } | |
11568 } | |
11569 case equal: { | |
11570 if (strict_) { | |
11571 if (never_nan_nan_) { | |
11572 return "CompareStub_EQ_STRICT_NO_NAN"; | |
11573 } else { | |
11574 return "CompareStub_EQ_STRICT"; | |
11575 } | |
11576 } else { | |
11577 if (never_nan_nan_) { | |
11578 return "CompareStub_EQ_NO_NAN"; | |
11579 } else { | |
11580 return "CompareStub_EQ"; | |
11581 } | |
11582 } | |
11583 } | |
11584 default: return "CompareStub"; | |
11585 } | |
11586 } | |
11587 | |
11588 | |
11589 int CompareStub::MinorKey() { | 11752 int CompareStub::MinorKey() { |
11590 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | 11753 // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
11591 // stubs the never NaN NaN condition is only taken into account if the | 11754 // stubs the never NaN NaN condition is only taken into account if the |
11592 // condition is equals. | 11755 // condition is equals. |
11593 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); | 11756 ASSERT(static_cast<unsigned>(cc_) < (1 << 13)); |
11594 return ConditionField::encode(static_cast<unsigned>(cc_)) | 11757 return ConditionField::encode(static_cast<unsigned>(cc_)) |
11595 | StrictField::encode(strict_) | 11758 | StrictField::encode(strict_) |
11596 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false); | 11759 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) |
| 11760 | IncludeNumberCompareField::encode(include_number_compare_); |
11597 } | 11761 } |
11598 | 11762 |
11599 | 11763 |
| 11764 // Unfortunately you have to run without snapshots to see most of these |
| 11765 // names in the profile since most compare stubs end up in the snapshot. |
| 11766 const char* CompareStub::GetName() { |
| 11767 if (name_ != NULL) return name_; |
| 11768 const int kMaxNameLength = 100; |
| 11769 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); |
| 11770 if (name_ == NULL) return "OOM"; |
| 11771 |
| 11772 const char* cc_name; |
| 11773 switch (cc_) { |
| 11774 case less: cc_name = "LT"; break; |
| 11775 case greater: cc_name = "GT"; break; |
| 11776 case less_equal: cc_name = "LE"; break; |
| 11777 case greater_equal: cc_name = "GE"; break; |
| 11778 case equal: cc_name = "EQ"; break; |
| 11779 case not_equal: cc_name = "NE"; break; |
| 11780 default: cc_name = "UnknownCondition"; break; |
| 11781 } |
| 11782 |
| 11783 const char* strict_name = ""; |
| 11784 if (strict_ && (cc_ == equal || cc_ == not_equal)) { |
| 11785 strict_name = "_STRICT"; |
| 11786 } |
| 11787 |
| 11788 const char* never_nan_nan_name = ""; |
| 11789 if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) { |
| 11790 never_nan_nan_name = "_NO_NAN"; |
| 11791 } |
| 11792 |
| 11793 const char* include_number_compare_name = ""; |
| 11794 if (!include_number_compare_) { |
| 11795 include_number_compare_name = "_NO_NUMBER"; |
| 11796 } |
| 11797 |
| 11798 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 11799 "CompareStub_%s%s%s%s", |
| 11800 cc_name, |
| 11801 strict_name, |
| 11802 never_nan_nan_name, |
| 11803 include_number_compare_name); |
| 11804 return name_; |
| 11805 } |
| 11806 |
| 11807 |
11600 void StringAddStub::Generate(MacroAssembler* masm) { | 11808 void StringAddStub::Generate(MacroAssembler* masm) { |
11601 Label string_add_runtime; | 11809 Label string_add_runtime; |
11602 | 11810 |
11603 // Load the two arguments. | 11811 // Load the two arguments. |
11604 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 11812 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
11605 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 11813 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
11606 | 11814 |
11607 // Make sure that both arguments are strings if not known in advance. | 11815 // Make sure that both arguments are strings if not known in advance. |
11608 if (string_check_) { | 11816 if (string_check_) { |
11609 __ test(eax, Immediate(kSmiTagMask)); | 11817 __ test(eax, Immediate(kSmiTagMask)); |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12220 | 12428 |
12221 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 12429 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
12222 Register left, | 12430 Register left, |
12223 Register right, | 12431 Register right, |
12224 Register scratch1, | 12432 Register scratch1, |
12225 Register scratch2, | 12433 Register scratch2, |
12226 Register scratch3) { | 12434 Register scratch3) { |
12227 Label result_not_equal; | 12435 Label result_not_equal; |
12228 Label result_greater; | 12436 Label result_greater; |
12229 Label compare_lengths; | 12437 Label compare_lengths; |
| 12438 |
| 12439 __ IncrementCounter(&Counters::string_compare_native, 1); |
| 12440 |
12230 // Find minimum length. | 12441 // Find minimum length. |
12231 Label left_shorter; | 12442 Label left_shorter; |
12232 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 12443 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
12233 __ mov(scratch3, scratch1); | 12444 __ mov(scratch3, scratch1); |
12234 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); | 12445 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
12235 | 12446 |
12236 Register length_delta = scratch3; | 12447 Register length_delta = scratch3; |
12237 | 12448 |
12238 __ j(less_equal, &left_shorter); | 12449 __ j(less_equal, &left_shorter); |
12239 // Right string is shorter. Change scratch1 to be length of right string. | 12450 // 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... |
12317 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 12528 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
12318 __ IncrementCounter(&Counters::string_compare_native, 1); | 12529 __ IncrementCounter(&Counters::string_compare_native, 1); |
12319 __ ret(2 * kPointerSize); | 12530 __ ret(2 * kPointerSize); |
12320 | 12531 |
12321 __ bind(¬_same); | 12532 __ bind(¬_same); |
12322 | 12533 |
12323 // Check that both objects are sequential ascii strings. | 12534 // Check that both objects are sequential ascii strings. |
12324 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 12535 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
12325 | 12536 |
12326 // Compare flat ascii strings. | 12537 // Compare flat ascii strings. |
12327 __ IncrementCounter(&Counters::string_compare_native, 1); | |
12328 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 12538 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
12329 | 12539 |
12330 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12540 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
12331 // tagged as a small integer. | 12541 // tagged as a small integer. |
12332 __ bind(&runtime); | 12542 __ bind(&runtime); |
12333 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12543 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
12334 } | 12544 } |
12335 | 12545 |
12336 #undef __ | 12546 #undef __ |
12337 | 12547 |
12338 } } // namespace v8::internal | 12548 } } // namespace v8::internal |
OLD | NEW |