Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 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 |