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 | |
915 // Code pattern for loading floating point values. Input values must | 914 // Code pattern for loading floating point values. Input values must |
916 // be either smi or heap number objects (fp values). Requirements: | 915 // be either smi or heap number objects (fp values). Requirements: |
917 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. | 916 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. |
918 // Returns operands as floating point numbers on FPU stack. | 917 // Returns operands as floating point numbers on FPU stack. |
919 static void LoadFloatOperands(MacroAssembler* masm, | 918 static void LoadFloatOperands(MacroAssembler* masm, |
920 Register scratch, | 919 Register scratch, |
921 ArgLocation arg_location = ARGS_ON_STACK); | 920 ArgLocation arg_location = ARGS_ON_STACK); |
922 | 921 |
923 // Similar to LoadFloatOperand but assumes that both operands are smis. | 922 // Similar to LoadFloatOperand but assumes that both operands are smis. |
924 // Expects operands in edx, eax. | 923 // Expects operands in edx, eax. |
925 static void LoadFloatSmis(MacroAssembler* masm, Register scratch); | 924 static void LoadFloatSmis(MacroAssembler* masm, Register scratch); |
926 | 925 |
927 // Test if operands are smi or number objects (fp). Requirements: | 926 // Test if operands are smi or number objects (fp). Requirements: |
928 // operand_1 in eax, operand_2 in edx; falls through on float | 927 // operand_1 in eax, operand_2 in edx; falls through on float |
929 // operands, jumps to the non_float label otherwise. | 928 // operands, jumps to the non_float label otherwise. |
930 static void CheckFloatOperands(MacroAssembler* masm, | 929 static void CheckFloatOperands(MacroAssembler* masm, |
931 Label* non_float, | 930 Label* non_float, |
932 Register scratch); | 931 Register scratch); |
933 | |
934 // Takes the operands in edx and eax and loads them as integers in eax | 932 // Takes the operands in edx and eax and loads them as integers in eax |
935 // and ecx. | 933 // and ecx. |
936 static void LoadAsIntegers(MacroAssembler* masm, | 934 static void LoadAsIntegers(MacroAssembler* masm, |
937 NumberInfo number_info, | 935 NumberInfo number_info, |
938 bool use_sse3, | 936 bool use_sse3, |
939 Label* operand_conversion_failure); | 937 Label* operand_conversion_failure); |
940 static void LoadNumbersAsIntegers(MacroAssembler* masm, | 938 static void LoadNumbersAsIntegers(MacroAssembler* masm, |
941 NumberInfo number_info, | 939 NumberInfo number_info, |
942 bool use_sse3, | 940 bool use_sse3, |
943 Label* operand_conversion_failure); | 941 Label* operand_conversion_failure); |
944 static void LoadUnknownsAsIntegers(MacroAssembler* masm, | 942 static void LoadUnknownsAsIntegers(MacroAssembler* masm, |
945 bool use_sse3, | 943 bool use_sse3, |
946 Label* operand_conversion_failure); | 944 Label* operand_conversion_failure); |
947 | 945 |
948 // Test if operands are smis or heap numbers and load them | 946 // Test if operands are smis or heap numbers and load them |
949 // into xmm0 and xmm1 if they are. Operands are in edx and eax. | 947 // into xmm0 and xmm1 if they are. Operands are in edx and eax. |
950 // Leaves operands unchanged. | 948 // Leaves operands unchanged. |
951 static void LoadSSE2Operands(MacroAssembler* masm); | 949 static void LoadSSE2Operands(MacroAssembler* masm); |
952 | |
953 // Test if operands are numbers (smi or HeapNumber objects), and load | 950 // Test if operands are numbers (smi or HeapNumber objects), and load |
954 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | 951 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
955 // either operand is not a number. Operands are in edx and eax. | 952 // either operand is not a number. Operands are in edx and eax. |
956 // Leaves operands unchanged. | 953 // Leaves operands unchanged. |
957 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); | 954 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); |
958 | 955 |
959 // Similar to LoadSSE2Operands but assumes that both operands are smis. | 956 // Similar to LoadSSE2Operands but assumes that both operands are smis. |
960 // Expects operands in edx, eax. | 957 // Expects operands in edx, eax. |
961 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); | 958 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); |
962 }; | 959 }; |
(...skipping 1394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2357 | 2354 |
2358 static bool CouldBeNaN(const Result& result) { | 2355 static bool CouldBeNaN(const Result& result) { |
2359 if (result.number_info().IsSmi()) return false; | 2356 if (result.number_info().IsSmi()) return false; |
2360 if (result.number_info().IsInteger32()) return false; | 2357 if (result.number_info().IsInteger32()) return false; |
2361 if (!result.is_constant()) return true; | 2358 if (!result.is_constant()) return true; |
2362 if (!result.handle()->IsHeapNumber()) return false; | 2359 if (!result.handle()->IsHeapNumber()) return false; |
2363 return isnan(HeapNumber::cast(*result.handle())->value()); | 2360 return isnan(HeapNumber::cast(*result.handle())->value()); |
2364 } | 2361 } |
2365 | 2362 |
2366 | 2363 |
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 | |
2383 void CodeGenerator::Comparison(AstNode* node, | 2364 void CodeGenerator::Comparison(AstNode* node, |
2384 Condition cc, | 2365 Condition cc, |
2385 bool strict, | 2366 bool strict, |
2386 ControlDestination* dest) { | 2367 ControlDestination* dest) { |
2387 // Strict only makes sense for equality comparisons. | 2368 // Strict only makes sense for equality comparisons. |
2388 ASSERT(!strict || cc == equal); | 2369 ASSERT(!strict || cc == equal); |
2389 | 2370 |
2390 Result left_side; | 2371 Result left_side; |
2391 Result right_side; | 2372 Result right_side; |
2392 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 2373 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2443 } | 2424 } |
2444 } else { | 2425 } else { |
2445 // Only one side is a constant Smi. | 2426 // Only one side is a constant Smi. |
2446 // If left side is a constant Smi, reverse the operands. | 2427 // If left side is a constant Smi, reverse the operands. |
2447 // Since one side is a constant Smi, conversion order does not matter. | 2428 // Since one side is a constant Smi, conversion order does not matter. |
2448 if (left_side_constant_smi) { | 2429 if (left_side_constant_smi) { |
2449 Result temp = left_side; | 2430 Result temp = left_side; |
2450 left_side = right_side; | 2431 left_side = right_side; |
2451 right_side = temp; | 2432 right_side = temp; |
2452 cc = ReverseCondition(cc); | 2433 cc = ReverseCondition(cc); |
2453 // This may re-introduce greater or less_equal as the value of cc. | 2434 // This may reintroduce greater or less_equal as the value of cc. |
2454 // CompareStub and the inline code both support all values of cc. | 2435 // CompareStub and the inline code both support all values of cc. |
2455 } | 2436 } |
2456 // Implement comparison against a constant Smi, inlining the case | 2437 // Implement comparison against a constant Smi, inlining the case |
2457 // where both sides are Smis. | 2438 // where both sides are Smis. |
2458 left_side.ToRegister(); | 2439 left_side.ToRegister(); |
2459 Register left_reg = left_side.reg(); | 2440 Register left_reg = left_side.reg(); |
2460 Handle<Object> right_val = right_side.handle(); | 2441 Handle<Object> right_val = right_side.handle(); |
2461 | 2442 |
2462 // Here we split control flow to the stub call and inlined cases | 2443 // Here we split control flow to the stub call and inlined cases |
2463 // before finally splitting it to the control destination. We use | 2444 // before finally splitting it to the control destination. We use |
(...skipping 28 matching lines...) Expand all Loading... |
2492 } else { | 2473 } else { |
2493 Result temp = allocator()->Allocate(); | 2474 Result temp = allocator()->Allocate(); |
2494 __ mov(temp.reg(), Immediate(value)); | 2475 __ mov(temp.reg(), Immediate(value)); |
2495 __ cvtsi2sd(xmm0, Operand(temp.reg())); | 2476 __ cvtsi2sd(xmm0, Operand(temp.reg())); |
2496 temp.Unuse(); | 2477 temp.Unuse(); |
2497 } | 2478 } |
2498 __ comisd(xmm1, xmm0); | 2479 __ comisd(xmm1, xmm0); |
2499 // Jump to builtin for NaN. | 2480 // Jump to builtin for NaN. |
2500 not_number.Branch(parity_even, &left_side); | 2481 not_number.Branch(parity_even, &left_side); |
2501 left_side.Unuse(); | 2482 left_side.Unuse(); |
2502 dest->true_target()->Branch(DoubleCondition(cc)); | 2483 Condition double_cc = 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); |
2503 dest->false_target()->Jump(); | 2493 dest->false_target()->Jump(); |
2504 not_number.Bind(&left_side); | 2494 not_number.Bind(&left_side); |
2505 } | 2495 } |
2506 | 2496 |
2507 // Setup and call the compare stub. | 2497 // Setup and call the compare stub. |
2508 CompareStub stub(cc, strict, kCantBothBeNaN); | 2498 CompareStub stub(cc, strict, kCantBothBeNaN); |
2509 Result result = frame_->CallStub(&stub, &left_side, &right_side); | 2499 Result result = frame_->CallStub(&stub, &left_side, &right_side); |
2510 result.ToRegister(); | 2500 result.ToRegister(); |
2511 __ cmp(result.reg(), 0); | 2501 __ cmp(result.reg(), 0); |
2512 result.Unuse(); | 2502 result.Unuse(); |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2691 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2681 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2692 Immediate(1)); | 2682 Immediate(1)); |
2693 __ bind(&characters_were_different); | 2683 __ bind(&characters_were_different); |
2694 } | 2684 } |
2695 temp2.Unuse(); | 2685 temp2.Unuse(); |
2696 left_side.Unuse(); | 2686 left_side.Unuse(); |
2697 right_side.Unuse(); | 2687 right_side.Unuse(); |
2698 dest->Split(cc); | 2688 dest->Split(cc); |
2699 } | 2689 } |
2700 } else { | 2690 } else { |
2701 // Neither side is a constant Smi, constant 1-char string or constant null. | 2691 // Neither side is a constant Smi or null. |
2702 // If either side is a non-smi constant, or known to be a heap number skip | 2692 // If either side is a non-smi constant, skip the smi check. |
2703 // the smi check. | |
2704 bool known_non_smi = | 2693 bool known_non_smi = |
2705 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 2694 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
2706 (right_side.is_constant() && !right_side.handle()->IsSmi()) || | 2695 (right_side.is_constant() && !right_side.handle()->IsSmi()); |
2707 left_side.number_info().IsHeapNumber() || | |
2708 right_side.number_info().IsHeapNumber(); | |
2709 NaNInformation nan_info = | 2696 NaNInformation nan_info = |
2710 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? | 2697 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? |
2711 kBothCouldBeNaN : | 2698 kBothCouldBeNaN : |
2712 kCantBothBeNaN; | 2699 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. | |
2729 left_side.ToRegister(); | 2700 left_side.ToRegister(); |
2730 right_side.ToRegister(); | 2701 right_side.ToRegister(); |
2731 | 2702 |
2732 if (known_non_smi) { | 2703 if (known_non_smi) { |
2733 // Inline the equality check if both operands can't be a NaN. If both | 2704 // When non-smi, call out to the compare stub. |
2734 // objects are the same they are equal. | 2705 CompareStub stub(cc, strict, nan_info); |
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); | |
2748 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2706 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2749 if (cc == equal) { | 2707 if (cc == equal) { |
2750 __ test(answer.reg(), Operand(answer.reg())); | 2708 __ test(answer.reg(), Operand(answer.reg())); |
2751 } else { | 2709 } else { |
2752 __ cmp(answer.reg(), 0); | 2710 __ cmp(answer.reg(), 0); |
2753 } | 2711 } |
2754 answer.Unuse(); | 2712 answer.Unuse(); |
2755 dest->Split(cc); | 2713 dest->Split(cc); |
2756 } else { | 2714 } else { |
2757 // Here we split control flow to the stub call and inlined cases | 2715 // Here we split control flow to the stub call and inlined cases |
2758 // before finally splitting it to the control destination. We use | 2716 // before finally splitting it to the control destination. We use |
2759 // a jump target and branching to duplicate the virtual frame at | 2717 // a jump target and branching to duplicate the virtual frame at |
2760 // the first split. We manually handle the off-frame references | 2718 // the first split. We manually handle the off-frame references |
2761 // by reconstituting them on the non-fall-through path. | 2719 // by reconstituting them on the non-fall-through path. |
2762 JumpTarget is_smi; | 2720 JumpTarget is_smi; |
2763 Register left_reg = left_side.reg(); | 2721 Register left_reg = left_side.reg(); |
2764 Register right_reg = right_side.reg(); | 2722 Register right_reg = right_side.reg(); |
2765 | 2723 |
2766 // In-line check for comparing two smis. | |
2767 Result temp = allocator_->Allocate(); | 2724 Result temp = allocator_->Allocate(); |
2768 ASSERT(temp.is_valid()); | 2725 ASSERT(temp.is_valid()); |
2769 __ mov(temp.reg(), left_side.reg()); | 2726 __ mov(temp.reg(), left_side.reg()); |
2770 __ or_(temp.reg(), Operand(right_side.reg())); | 2727 __ or_(temp.reg(), Operand(right_side.reg())); |
2771 __ test(temp.reg(), Immediate(kSmiTagMask)); | 2728 __ test(temp.reg(), Immediate(kSmiTagMask)); |
2772 temp.Unuse(); | 2729 temp.Unuse(); |
2773 is_smi.Branch(zero, taken); | 2730 is_smi.Branch(zero, taken); |
2774 | 2731 // When non-smi, call out to the compare stub. |
2775 // Inline the equality check if both operands can't be a NaN. If both | 2732 CompareStub stub(cc, strict, nan_info); |
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); | |
2790 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2733 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2791 if (cc == equal) { | 2734 if (cc == equal) { |
2792 __ test(answer.reg(), Operand(answer.reg())); | 2735 __ test(answer.reg(), Operand(answer.reg())); |
2793 } else { | 2736 } else { |
2794 __ cmp(answer.reg(), 0); | 2737 __ cmp(answer.reg(), 0); |
2795 } | 2738 } |
2796 answer.Unuse(); | 2739 answer.Unuse(); |
2797 dest->true_target()->Branch(cc); | 2740 dest->true_target()->Branch(cc); |
2798 dest->false_target()->Jump(); | 2741 dest->false_target()->Jump(); |
2799 | 2742 |
2800 is_smi.Bind(); | 2743 is_smi.Bind(); |
2801 left_side = Result(left_reg); | 2744 left_side = Result(left_reg); |
2802 right_side = Result(right_reg); | 2745 right_side = Result(right_reg); |
2803 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2746 __ cmp(left_side.reg(), Operand(right_side.reg())); |
2804 right_side.Unuse(); | 2747 right_side.Unuse(); |
2805 left_side.Unuse(); | 2748 left_side.Unuse(); |
2806 dest->Split(cc); | 2749 dest->Split(cc); |
2807 } | 2750 } |
2808 } | 2751 } |
2809 } | 2752 } |
2810 | 2753 |
2811 | 2754 |
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 Result* left_side, | |
2837 Result* right_side) { | |
2838 Label done; | |
2839 if (operand->number_info().IsHeapNumber()) { | |
2840 // Operand is known to be a heap number, just load it. | |
2841 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2842 } else if (operand->number_info().IsSmi()) { | |
2843 // Operand is known to be a smi. Convert it to double and keep the original | |
2844 // smi. | |
2845 __ SmiUntag(operand->reg()); | |
2846 __ push(operand->reg()); | |
2847 __ fild_s(Operand(esp, 0)); | |
2848 __ pop(operand->reg()); | |
2849 __ SmiTag(operand->reg()); | |
2850 } else { | |
2851 // Operand type not known, check for smi otherwise assume heap number. | |
2852 Label smi; | |
2853 __ test(operand->reg(), Immediate(kSmiTagMask)); | |
2854 __ j(zero, &smi); | |
2855 __ fld_d(FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2856 __ jmp(&done); | |
2857 __ bind(&smi); | |
2858 __ SmiUntag(operand->reg()); | |
2859 __ push(operand->reg()); | |
2860 __ fild_s(Operand(esp, 0)); | |
2861 __ pop(operand->reg()); | |
2862 __ SmiTag(operand->reg()); | |
2863 __ jmp(&done); | |
2864 } | |
2865 __ bind(&done); | |
2866 } | |
2867 | |
2868 | |
2869 // Load a comparison operand into into a XMM register. Jump to not_numbers jump | |
2870 // target passing the left and right result if the operand is not a number. | |
2871 static void LoadComparisonOperandSSE2(MacroAssembler* masm_, | |
2872 Result* operand, | |
2873 XMMRegister reg, | |
2874 Result* left_side, | |
2875 Result* right_side, | |
2876 JumpTarget* not_numbers) { | |
2877 Label done; | |
2878 if (operand->number_info().IsHeapNumber()) { | |
2879 // Operand is known to be a heap number, just load it. | |
2880 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2881 } else if (operand->number_info().IsSmi()) { | |
2882 // Operand is known to be a smi. Convert it to double and keep the original | |
2883 // smi. | |
2884 __ SmiUntag(operand->reg()); | |
2885 __ cvtsi2sd(reg, Operand(operand->reg())); | |
2886 __ SmiTag(left_side->reg()); | |
2887 } else { | |
2888 // Operand type not known, check for smi or heap number. | |
2889 Label smi; | |
2890 __ test(operand->reg(), Immediate(kSmiTagMask)); | |
2891 __ j(zero, &smi); | |
2892 if (!operand->number_info().IsNumber()) { | |
2893 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), | |
2894 Immediate(Factory::heap_number_map())); | |
2895 not_numbers->Branch(not_equal, left_side, right_side, taken); | |
2896 } | |
2897 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | |
2898 __ jmp(&done); | |
2899 | |
2900 __ bind(&smi); | |
2901 // Comvert smi to float and keep the original smi. | |
2902 __ SmiUntag(operand->reg()); | |
2903 __ cvtsi2sd(reg, Operand(operand->reg())); | |
2904 __ SmiTag(operand->reg()); | |
2905 __ jmp(&done); | |
2906 } | |
2907 __ bind(&done); | |
2908 } | |
2909 | |
2910 | |
2911 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, | |
2912 Result* right_side, | |
2913 Condition cc, | |
2914 ControlDestination* dest) { | |
2915 ASSERT(left_side->is_register()); | |
2916 ASSERT(right_side->is_register()); | |
2917 | |
2918 JumpTarget not_numbers; | |
2919 if (CpuFeatures::IsSupported(SSE2)) { | |
2920 CpuFeatures::Scope use_sse2(SSE2); | |
2921 | |
2922 // Load left and right operand into registers xmm0 and xmm1 and compare. | |
2923 LoadComparisonOperandSSE2(masm_, left_side, xmm0, left_side, right_side, | |
2924 ¬_numbers); | |
2925 LoadComparisonOperandSSE2(masm_, right_side, xmm1, left_side, right_side, | |
2926 ¬_numbers); | |
2927 __ comisd(xmm0, xmm1); | |
2928 } else { | |
2929 Label check_right, compare; | |
2930 | |
2931 // Make sure that both comparison operands are numbers. | |
2932 CheckComparisonOperand(masm_, left_side, left_side, right_side, | |
2933 ¬_numbers); | |
2934 CheckComparisonOperand(masm_, right_side, left_side, right_side, | |
2935 ¬_numbers); | |
2936 | |
2937 // Load right and left operand to FPU stack and compare. | |
2938 LoadComparisonOperand(masm_, right_side, left_side, right_side); | |
2939 LoadComparisonOperand(masm_, left_side, left_side, right_side); | |
2940 __ FCmp(); | |
2941 } | |
2942 | |
2943 // Bail out if a NaN is involved. | |
2944 not_numbers.Branch(parity_even, left_side, right_side, not_taken); | |
2945 | |
2946 // Split to destination targets based on comparison. | |
2947 left_side->Unuse(); | |
2948 right_side->Unuse(); | |
2949 dest->true_target()->Branch(DoubleCondition(cc)); | |
2950 dest->false_target()->Jump(); | |
2951 | |
2952 not_numbers.Bind(left_side, right_side); | |
2953 } | |
2954 | |
2955 | |
2956 // Call the function just below TOS on the stack with the given | 2755 // Call the function just below TOS on the stack with the given |
2957 // arguments. The receiver is the TOS. | 2756 // arguments. The receiver is the TOS. |
2958 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 2757 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
2959 CallFunctionFlags flags, | 2758 CallFunctionFlags flags, |
2960 int position) { | 2759 int position) { |
2961 // Push the arguments ("left-to-right") on the stack. | 2760 // Push the arguments ("left-to-right") on the stack. |
2962 int arg_count = args->length(); | 2761 int arg_count = args->length(); |
2963 for (int i = 0; i < arg_count; i++) { | 2762 for (int i = 0; i < arg_count; i++) { |
2964 Load(args->at(i)); | 2763 Load(args->at(i)); |
2965 } | 2764 } |
(...skipping 8105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11071 } | 10870 } |
11072 __ bind(&slow); | 10871 __ bind(&slow); |
11073 } | 10872 } |
11074 | 10873 |
11075 // Push arguments below the return address. | 10874 // Push arguments below the return address. |
11076 __ pop(ecx); | 10875 __ pop(ecx); |
11077 __ push(eax); | 10876 __ push(eax); |
11078 __ push(edx); | 10877 __ push(edx); |
11079 __ push(ecx); | 10878 __ push(ecx); |
11080 | 10879 |
11081 // Generate the number comparison code. | 10880 // Inlined floating point compare. |
11082 if (include_number_compare_) { | 10881 // Call builtin if operands are not floating point or smi. |
11083 Label non_number_comparison; | 10882 Label check_for_symbols; |
11084 Label unordered; | 10883 Label unordered; |
11085 if (CpuFeatures::IsSupported(SSE2)) { | 10884 if (CpuFeatures::IsSupported(SSE2)) { |
11086 CpuFeatures::Scope use_sse2(SSE2); | 10885 CpuFeatures::Scope use_sse2(SSE2); |
11087 CpuFeatures::Scope use_cmov(CMOV); | 10886 CpuFeatures::Scope use_cmov(CMOV); |
11088 | 10887 |
11089 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); | 10888 FloatingPointHelper::LoadSSE2Operands(masm, &check_for_symbols); |
11090 __ comisd(xmm0, xmm1); | 10889 __ comisd(xmm0, xmm1); |
11091 | 10890 |
11092 // Don't base result on EFLAGS when a NaN is involved. | 10891 // Jump to builtin for NaN. |
11093 __ j(parity_even, &unordered, not_taken); | 10892 __ j(parity_even, &unordered, not_taken); |
11094 // Return a result of -1, 0, or 1, based on EFLAGS. | 10893 __ mov(eax, 0); // equal |
11095 __ mov(eax, 0); // equal | 10894 __ mov(ecx, Immediate(Smi::FromInt(1))); |
11096 __ mov(ecx, Immediate(Smi::FromInt(1))); | 10895 __ cmov(above, eax, Operand(ecx)); |
11097 __ cmov(above, eax, Operand(ecx)); | 10896 __ mov(ecx, Immediate(Smi::FromInt(-1))); |
11098 __ mov(ecx, Immediate(Smi::FromInt(-1))); | 10897 __ cmov(below, eax, Operand(ecx)); |
11099 __ cmov(below, eax, Operand(ecx)); | 10898 __ ret(2 * kPointerSize); |
11100 __ ret(2 * kPointerSize); | 10899 } else { |
11101 } else { | 10900 FloatingPointHelper::CheckFloatOperands(masm, &check_for_symbols, ebx); |
11102 FloatingPointHelper::CheckFloatOperands( | 10901 FloatingPointHelper::LoadFloatOperands(masm, ecx); |
11103 masm, &non_number_comparison, ebx); | 10902 __ FCmp(); |
11104 FloatingPointHelper::LoadFloatOperands(masm, ecx); | |
11105 __ FCmp(); | |
11106 | 10903 |
11107 // Don't base result on EFLAGS when a NaN is involved. | 10904 // Jump to builtin for NaN. |
11108 __ j(parity_even, &unordered, not_taken); | 10905 __ j(parity_even, &unordered, not_taken); |
11109 | 10906 |
11110 Label below_label, above_label; | 10907 Label below_lbl, above_lbl; |
11111 // Return a result of -1, 0, or 1, based on EFLAGS. In all cases remove | 10908 // Return a result of -1, 0, or 1, to indicate result of comparison. |
11112 // two arguments from the stack as they have been pushed in preparation | 10909 __ j(below, &below_lbl, not_taken); |
11113 // of a possible runtime call. | 10910 __ j(above, &above_lbl, not_taken); |
11114 __ j(below, &below_label, not_taken); | |
11115 __ j(above, &above_label, not_taken); | |
11116 | 10911 |
11117 __ xor_(eax, Operand(eax)); | 10912 __ xor_(eax, Operand(eax)); // equal |
11118 __ ret(2 * kPointerSize); | 10913 // Both arguments were pushed in case a runtime call was needed. |
| 10914 __ ret(2 * kPointerSize); |
11119 | 10915 |
11120 __ bind(&below_label); | 10916 __ bind(&below_lbl); |
11121 __ mov(eax, Immediate(Smi::FromInt(-1))); | 10917 __ mov(eax, Immediate(Smi::FromInt(-1))); |
11122 __ ret(2 * kPointerSize); | 10918 __ ret(2 * kPointerSize); |
11123 | 10919 |
11124 __ bind(&above_label); | 10920 __ bind(&above_lbl); |
11125 __ mov(eax, Immediate(Smi::FromInt(1))); | 10921 __ mov(eax, Immediate(Smi::FromInt(1))); |
11126 __ ret(2 * kPointerSize); | |
11127 } | |
11128 | |
11129 // If one of the numbers was NaN, then the result is always false. | |
11130 // The cc is never not-equal. | |
11131 __ bind(&unordered); | |
11132 ASSERT(cc_ != not_equal); | |
11133 if (cc_ == less || cc_ == less_equal) { | |
11134 __ mov(eax, Immediate(Smi::FromInt(1))); | |
11135 } else { | |
11136 __ mov(eax, Immediate(Smi::FromInt(-1))); | |
11137 } | |
11138 __ ret(2 * kPointerSize); // eax, edx were pushed | 10922 __ ret(2 * kPointerSize); // eax, edx were pushed |
11139 | |
11140 // The number comparison code did not provide a valid result. | |
11141 __ bind(&non_number_comparison); | |
11142 } | 10923 } |
| 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 |
11143 | 10934 |
11144 // Fast negative check for symbol-to-symbol equality. | 10935 // Fast negative check for symbol-to-symbol equality. |
| 10936 __ bind(&check_for_symbols); |
11145 Label check_for_strings; | 10937 Label check_for_strings; |
11146 if (cc_ == equal) { | 10938 if (cc_ == equal) { |
11147 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); | 10939 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); |
11148 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); | 10940 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); |
11149 | 10941 |
11150 // We've already checked for object identity, so if both operands | 10942 // We've already checked for object identity, so if both operands |
11151 // are symbols they aren't equal. Register eax already holds a | 10943 // are symbols they aren't equal. Register eax already holds a |
11152 // non-zero value, which indicates not equal, so just return. | 10944 // non-zero value, which indicates not equal, so just return. |
11153 __ ret(2 * kPointerSize); | 10945 __ ret(2 * kPointerSize); |
11154 } | 10946 } |
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11744 __ bind(&is_not_instance); | 11536 __ bind(&is_not_instance); |
11745 __ Set(eax, Immediate(Smi::FromInt(1))); | 11537 __ Set(eax, Immediate(Smi::FromInt(1))); |
11746 __ ret(2 * kPointerSize); | 11538 __ ret(2 * kPointerSize); |
11747 | 11539 |
11748 // Slow-case: Go through the JavaScript implementation. | 11540 // Slow-case: Go through the JavaScript implementation. |
11749 __ bind(&slow); | 11541 __ bind(&slow); |
11750 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 11542 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
11751 } | 11543 } |
11752 | 11544 |
11753 | 11545 |
| 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 |
11754 int CompareStub::MinorKey() { | 11589 int CompareStub::MinorKey() { |
11755 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | 11590 // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
11756 // stubs the never NaN NaN condition is only taken into account if the | 11591 // stubs the never NaN NaN condition is only taken into account if the |
11757 // condition is equals. | 11592 // condition is equals. |
11758 ASSERT(static_cast<unsigned>(cc_) < (1 << 13)); | 11593 ASSERT(static_cast<unsigned>(cc_) < (1 << 14)); |
11759 return ConditionField::encode(static_cast<unsigned>(cc_)) | 11594 return ConditionField::encode(static_cast<unsigned>(cc_)) |
11760 | StrictField::encode(strict_) | 11595 | StrictField::encode(strict_) |
11761 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) | 11596 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false); |
11762 | IncludeNumberCompareField::encode(include_number_compare_); | |
11763 } | 11597 } |
11764 | 11598 |
11765 | 11599 |
11766 // Unfortunately you have to run without snapshots to see most of these | |
11767 // names in the profile since most compare stubs end up in the snapshot. | |
11768 const char* CompareStub::GetName() { | |
11769 if (name_ != NULL) return name_; | |
11770 const int kMaxNameLength = 100; | |
11771 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); | |
11772 if (name_ == NULL) return "OOM"; | |
11773 | |
11774 const char* cc_name; | |
11775 switch (cc_) { | |
11776 case less: cc_name = "LT"; break; | |
11777 case greater: cc_name = "GT"; break; | |
11778 case less_equal: cc_name = "LE"; break; | |
11779 case greater_equal: cc_name = "GE"; break; | |
11780 case equal: cc_name = "EQ"; break; | |
11781 case not_equal: cc_name = "NE"; break; | |
11782 default: cc_name = "UnknownCondition"; break; | |
11783 } | |
11784 | |
11785 const char* strict_name = ""; | |
11786 if (strict_ && (cc_ == equal || cc_ == not_equal)) { | |
11787 strict_name = "_STRICT"; | |
11788 } | |
11789 | |
11790 const char* never_nan_nan_name = ""; | |
11791 if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) { | |
11792 never_nan_nan_name = "_NO_NAN"; | |
11793 } | |
11794 | |
11795 const char* include_number_compare_name = ""; | |
11796 if (!include_number_compare_) { | |
11797 include_number_compare_name = "_NO_NUMBER"; | |
11798 } | |
11799 | |
11800 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | |
11801 "CompareStub_%s%s%s%s", | |
11802 cc_name, | |
11803 strict_name, | |
11804 never_nan_nan_name, | |
11805 include_number_compare_name); | |
11806 return name_; | |
11807 } | |
11808 | |
11809 | |
11810 void StringAddStub::Generate(MacroAssembler* masm) { | 11600 void StringAddStub::Generate(MacroAssembler* masm) { |
11811 Label string_add_runtime; | 11601 Label string_add_runtime; |
11812 | 11602 |
11813 // Load the two arguments. | 11603 // Load the two arguments. |
11814 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 11604 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
11815 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 11605 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
11816 | 11606 |
11817 // Make sure that both arguments are strings if not known in advance. | 11607 // Make sure that both arguments are strings if not known in advance. |
11818 if (string_check_) { | 11608 if (string_check_) { |
11819 __ test(eax, Immediate(kSmiTagMask)); | 11609 __ test(eax, Immediate(kSmiTagMask)); |
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12430 | 12220 |
12431 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 12221 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
12432 Register left, | 12222 Register left, |
12433 Register right, | 12223 Register right, |
12434 Register scratch1, | 12224 Register scratch1, |
12435 Register scratch2, | 12225 Register scratch2, |
12436 Register scratch3) { | 12226 Register scratch3) { |
12437 Label result_not_equal; | 12227 Label result_not_equal; |
12438 Label result_greater; | 12228 Label result_greater; |
12439 Label compare_lengths; | 12229 Label compare_lengths; |
12440 | |
12441 __ IncrementCounter(&Counters::string_compare_native, 1); | |
12442 | |
12443 // Find minimum length. | 12230 // Find minimum length. |
12444 Label left_shorter; | 12231 Label left_shorter; |
12445 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 12232 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
12446 __ mov(scratch3, scratch1); | 12233 __ mov(scratch3, scratch1); |
12447 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); | 12234 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
12448 | 12235 |
12449 Register length_delta = scratch3; | 12236 Register length_delta = scratch3; |
12450 | 12237 |
12451 __ j(less_equal, &left_shorter); | 12238 __ j(less_equal, &left_shorter); |
12452 // Right string is shorter. Change scratch1 to be length of right string. | 12239 // 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... |
12530 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 12317 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
12531 __ IncrementCounter(&Counters::string_compare_native, 1); | 12318 __ IncrementCounter(&Counters::string_compare_native, 1); |
12532 __ ret(2 * kPointerSize); | 12319 __ ret(2 * kPointerSize); |
12533 | 12320 |
12534 __ bind(¬_same); | 12321 __ bind(¬_same); |
12535 | 12322 |
12536 // Check that both objects are sequential ascii strings. | 12323 // Check that both objects are sequential ascii strings. |
12537 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 12324 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
12538 | 12325 |
12539 // Compare flat ascii strings. | 12326 // Compare flat ascii strings. |
| 12327 __ IncrementCounter(&Counters::string_compare_native, 1); |
12540 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 12328 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
12541 | 12329 |
12542 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12330 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
12543 // tagged as a small integer. | 12331 // tagged as a small integer. |
12544 __ bind(&runtime); | 12332 __ bind(&runtime); |
12545 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12333 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
12546 } | 12334 } |
12547 | 12335 |
12548 #undef __ | 12336 #undef __ |
12549 | 12337 |
12550 } } // namespace v8::internal | 12338 } } // namespace v8::internal |
OLD | NEW |