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 2469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2480 if (cc == greater || cc == less_equal) { | 2480 if (cc == greater || cc == less_equal) { |
2481 cc = ReverseCondition(cc); | 2481 cc = ReverseCondition(cc); |
2482 left_side = frame_->Pop(); | 2482 left_side = frame_->Pop(); |
2483 right_side = frame_->Pop(); | 2483 right_side = frame_->Pop(); |
2484 } else { | 2484 } else { |
2485 right_side = frame_->Pop(); | 2485 right_side = frame_->Pop(); |
2486 left_side = frame_->Pop(); | 2486 left_side = frame_->Pop(); |
2487 } | 2487 } |
2488 ASSERT(cc == less || cc == equal || cc == greater_equal); | 2488 ASSERT(cc == less || cc == equal || cc == greater_equal); |
2489 | 2489 |
2490 // If either side is a constant of some sort, we can probably optimize the | 2490 // If either side is a constant smi, optimize the comparison. |
2491 // comparison. | |
2492 bool left_side_constant_smi = false; | 2491 bool left_side_constant_smi = false; |
2493 bool left_side_constant_null = false; | 2492 bool left_side_constant_null = false; |
2494 bool left_side_constant_1_char_string = false; | 2493 bool left_side_constant_1_char_string = false; |
2495 if (left_side.is_constant()) { | 2494 if (left_side.is_constant()) { |
2496 left_side_constant_smi = left_side.handle()->IsSmi(); | 2495 left_side_constant_smi = left_side.handle()->IsSmi(); |
2497 left_side_constant_null = left_side.handle()->IsNull(); | 2496 left_side_constant_null = left_side.handle()->IsNull(); |
2498 left_side_constant_1_char_string = | 2497 left_side_constant_1_char_string = |
2499 (left_side.handle()->IsString() && | 2498 (left_side.handle()->IsString() && |
2500 String::cast(*left_side.handle())->length() == 1 && | 2499 String::cast(*left_side.handle())->length() == 1 && |
2501 String::cast(*left_side.handle())->IsAsciiRepresentation()); | 2500 String::cast(*left_side.handle())->IsAsciiRepresentation()); |
2502 } | 2501 } |
2503 bool right_side_constant_smi = false; | 2502 bool right_side_constant_smi = false; |
2504 bool right_side_constant_null = false; | 2503 bool right_side_constant_null = false; |
2505 bool right_side_constant_1_char_string = false; | 2504 bool right_side_constant_1_char_string = false; |
2506 if (right_side.is_constant()) { | 2505 if (right_side.is_constant()) { |
2507 right_side_constant_smi = right_side.handle()->IsSmi(); | 2506 right_side_constant_smi = right_side.handle()->IsSmi(); |
2508 right_side_constant_null = right_side.handle()->IsNull(); | 2507 right_side_constant_null = right_side.handle()->IsNull(); |
2509 right_side_constant_1_char_string = | 2508 right_side_constant_1_char_string = |
2510 (right_side.handle()->IsString() && | 2509 (right_side.handle()->IsString() && |
2511 String::cast(*right_side.handle())->length() == 1 && | 2510 String::cast(*right_side.handle())->length() == 1 && |
2512 String::cast(*right_side.handle())->IsAsciiRepresentation()); | 2511 String::cast(*right_side.handle())->IsAsciiRepresentation()); |
2513 } | 2512 } |
2514 | 2513 |
2515 if (left_side_constant_smi || right_side_constant_smi) { | 2514 if (left_side_constant_smi || right_side_constant_smi) { |
2516 if (left_side_constant_smi && right_side_constant_smi) { | 2515 bool is_loop_condition = (node->AsExpression() != NULL) && |
2517 // Trivial case, comparing two constants. | 2516 node->AsExpression()->is_loop_condition(); |
2518 int left_value = Smi::cast(*left_side.handle())->value(); | 2517 ConstantSmiComparison(cc, strict, dest, &left_side, &right_side, |
2519 int right_value = Smi::cast(*right_side.handle())->value(); | 2518 left_side_constant_smi, right_side_constant_smi, |
2520 switch (cc) { | 2519 is_loop_condition); |
2521 case less: | |
2522 dest->Goto(left_value < right_value); | |
2523 break; | |
2524 case equal: | |
2525 dest->Goto(left_value == right_value); | |
2526 break; | |
2527 case greater_equal: | |
2528 dest->Goto(left_value >= right_value); | |
2529 break; | |
2530 default: | |
2531 UNREACHABLE(); | |
2532 } | |
2533 } else { | |
2534 // Only one side is a constant Smi. | |
2535 // If left side is a constant Smi, reverse the operands. | |
2536 // Since one side is a constant Smi, conversion order does not matter. | |
2537 if (left_side_constant_smi) { | |
2538 Result temp = left_side; | |
2539 left_side = right_side; | |
2540 right_side = temp; | |
2541 cc = ReverseCondition(cc); | |
2542 // This may re-introduce greater or less_equal as the value of cc. | |
2543 // CompareStub and the inline code both support all values of cc. | |
2544 } | |
2545 // Implement comparison against a constant Smi, inlining the case | |
2546 // where both sides are Smis. | |
2547 left_side.ToRegister(); | |
2548 Register left_reg = left_side.reg(); | |
2549 Handle<Object> right_val = right_side.handle(); | |
2550 | |
2551 // Here we split control flow to the stub call and inlined cases | |
2552 // before finally splitting it to the control destination. We use | |
2553 // a jump target and branching to duplicate the virtual frame at | |
2554 // the first split. We manually handle the off-frame references | |
2555 // by reconstituting them on the non-fall-through path. | |
2556 | |
2557 if (left_side.is_smi()) { | |
2558 if (FLAG_debug_code) { | |
2559 __ AbortIfNotSmi(left_side.reg()); | |
2560 } | |
2561 } else { | |
2562 JumpTarget is_smi; | |
2563 __ test(left_side.reg(), Immediate(kSmiTagMask)); | |
2564 is_smi.Branch(zero, taken); | |
2565 | |
2566 bool is_loop_condition = (node->AsExpression() != NULL) && | |
2567 node->AsExpression()->is_loop_condition(); | |
2568 if (!is_loop_condition && | |
2569 CpuFeatures::IsSupported(SSE2) && | |
2570 right_val->IsSmi()) { | |
2571 // Right side is a constant smi and left side has been checked | |
2572 // not to be a smi. | |
2573 CpuFeatures::Scope use_sse2(SSE2); | |
2574 JumpTarget not_number; | |
2575 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | |
2576 Immediate(Factory::heap_number_map())); | |
2577 not_number.Branch(not_equal, &left_side); | |
2578 __ movdbl(xmm1, | |
2579 FieldOperand(left_reg, HeapNumber::kValueOffset)); | |
2580 int value = Smi::cast(*right_val)->value(); | |
2581 if (value == 0) { | |
2582 __ xorpd(xmm0, xmm0); | |
2583 } else { | |
2584 Result temp = allocator()->Allocate(); | |
2585 __ mov(temp.reg(), Immediate(value)); | |
2586 __ cvtsi2sd(xmm0, Operand(temp.reg())); | |
2587 temp.Unuse(); | |
2588 } | |
2589 __ ucomisd(xmm1, xmm0); | |
2590 // Jump to builtin for NaN. | |
2591 not_number.Branch(parity_even, &left_side); | |
2592 left_side.Unuse(); | |
2593 dest->true_target()->Branch(DoubleCondition(cc)); | |
2594 dest->false_target()->Jump(); | |
2595 not_number.Bind(&left_side); | |
2596 } | |
2597 | |
2598 // Setup and call the compare stub. | |
2599 CompareStub stub(cc, strict, kCantBothBeNaN); | |
2600 Result result = frame_->CallStub(&stub, &left_side, &right_side); | |
2601 result.ToRegister(); | |
2602 __ cmp(result.reg(), 0); | |
2603 result.Unuse(); | |
2604 dest->true_target()->Branch(cc); | |
2605 dest->false_target()->Jump(); | |
2606 | |
2607 is_smi.Bind(); | |
2608 } | |
2609 | |
2610 left_side = Result(left_reg); | |
2611 right_side = Result(right_val); | |
2612 // Test smi equality and comparison by signed int comparison. | |
2613 if (IsUnsafeSmi(right_side.handle())) { | |
2614 right_side.ToRegister(); | |
2615 __ cmp(left_side.reg(), Operand(right_side.reg())); | |
2616 } else { | |
2617 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle())); | |
2618 } | |
2619 left_side.Unuse(); | |
2620 right_side.Unuse(); | |
2621 dest->Split(cc); | |
2622 } | |
2623 | |
2624 } else if (cc == equal && | 2520 } else if (cc == equal && |
2625 (left_side_constant_null || right_side_constant_null)) { | 2521 (left_side_constant_null || right_side_constant_null)) { |
2626 // To make null checks efficient, we check if either the left side or | 2522 // To make null checks efficient, we check if either the left side or |
2627 // the right side is the constant 'null'. | 2523 // the right side is the constant 'null'. |
2628 // If so, we optimize the code by inlining a null check instead of | 2524 // If so, we optimize the code by inlining a null check instead of |
2629 // calling the (very) general runtime routine for checking equality. | 2525 // calling the (very) general runtime routine for checking equality. |
2630 Result operand = left_side_constant_null ? right_side : left_side; | 2526 Result operand = left_side_constant_null ? right_side : left_side; |
2631 right_side.Unuse(); | 2527 right_side.Unuse(); |
2632 left_side.Unuse(); | 2528 left_side.Unuse(); |
2633 operand.ToRegister(); | 2529 operand.ToRegister(); |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2875 right_side = Result(right_reg); | 2771 right_side = Result(right_reg); |
2876 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2772 __ cmp(left_side.reg(), Operand(right_side.reg())); |
2877 right_side.Unuse(); | 2773 right_side.Unuse(); |
2878 left_side.Unuse(); | 2774 left_side.Unuse(); |
2879 dest->Split(cc); | 2775 dest->Split(cc); |
2880 } | 2776 } |
2881 } | 2777 } |
2882 } | 2778 } |
2883 | 2779 |
2884 | 2780 |
| 2781 void CodeGenerator::ConstantSmiComparison(Condition cc, |
| 2782 bool strict, |
| 2783 ControlDestination* dest, |
| 2784 Result* left_side, |
| 2785 Result* right_side, |
| 2786 bool left_side_constant_smi, |
| 2787 bool right_side_constant_smi, |
| 2788 bool is_loop_condition) { |
| 2789 if (left_side_constant_smi && right_side_constant_smi) { |
| 2790 // Trivial case, comparing two constants. |
| 2791 int left_value = Smi::cast(*left_side->handle())->value(); |
| 2792 int right_value = Smi::cast(*right_side->handle())->value(); |
| 2793 switch (cc) { |
| 2794 case less: |
| 2795 dest->Goto(left_value < right_value); |
| 2796 break; |
| 2797 case equal: |
| 2798 dest->Goto(left_value == right_value); |
| 2799 break; |
| 2800 case greater_equal: |
| 2801 dest->Goto(left_value >= right_value); |
| 2802 break; |
| 2803 default: |
| 2804 UNREACHABLE(); |
| 2805 } |
| 2806 } else { |
| 2807 // Only one side is a constant Smi. |
| 2808 // If left side is a constant Smi, reverse the operands. |
| 2809 // Since one side is a constant Smi, conversion order does not matter. |
| 2810 if (left_side_constant_smi) { |
| 2811 Result* temp = left_side; |
| 2812 left_side = right_side; |
| 2813 right_side = temp; |
| 2814 cc = ReverseCondition(cc); |
| 2815 // This may re-introduce greater or less_equal as the value of cc. |
| 2816 // CompareStub and the inline code both support all values of cc. |
| 2817 } |
| 2818 // Implement comparison against a constant Smi, inlining the case |
| 2819 // where both sides are Smis. |
| 2820 left_side->ToRegister(); |
| 2821 Register left_reg = left_side->reg(); |
| 2822 Handle<Object> right_val = right_side->handle(); |
| 2823 |
| 2824 if (left_side->is_smi()) { |
| 2825 if (FLAG_debug_code) { |
| 2826 __ AbortIfNotSmi(left_reg); |
| 2827 } |
| 2828 // Test smi equality and comparison by signed int comparison. |
| 2829 if (IsUnsafeSmi(right_side->handle())) { |
| 2830 right_side->ToRegister(); |
| 2831 __ cmp(left_reg, Operand(right_side->reg())); |
| 2832 } else { |
| 2833 __ cmp(Operand(left_reg), Immediate(right_side->handle())); |
| 2834 } |
| 2835 left_side->Unuse(); |
| 2836 right_side->Unuse(); |
| 2837 dest->Split(cc); |
| 2838 } else { |
| 2839 // Only the case where the left side could possibly be a non-smi is left. |
| 2840 JumpTarget is_smi; |
| 2841 if (cc == equal) { |
| 2842 // We can do the equality comparison before the smi check. |
| 2843 __ cmp(Operand(left_reg), Immediate(right_side->handle())); |
| 2844 dest->true_target()->Branch(equal); |
| 2845 __ test(left_reg, Immediate(kSmiTagMask)); |
| 2846 dest->false_target()->Branch(zero); |
| 2847 } else { |
| 2848 // Do the smi check, then the comparison. |
| 2849 JumpTarget is_not_smi; |
| 2850 __ test(left_reg, Immediate(kSmiTagMask)); |
| 2851 is_smi.Branch(zero, left_side, right_side); |
| 2852 } |
| 2853 |
| 2854 // Jump or fall through to here if we are comparing a non-smi to a |
| 2855 // constant smi. If the non-smi is a heap number and this is not |
| 2856 // a loop condition, inline the floating point code. |
| 2857 if (!is_loop_condition && CpuFeatures::IsSupported(SSE2)) { |
| 2858 // Right side is a constant smi and left side has been checked |
| 2859 // not to be a smi. |
| 2860 CpuFeatures::Scope use_sse2(SSE2); |
| 2861 JumpTarget not_number; |
| 2862 __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
| 2863 Immediate(Factory::heap_number_map())); |
| 2864 not_number.Branch(not_equal, left_side); |
| 2865 __ movdbl(xmm1, |
| 2866 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
| 2867 int value = Smi::cast(*right_val)->value(); |
| 2868 if (value == 0) { |
| 2869 __ xorpd(xmm0, xmm0); |
| 2870 } else { |
| 2871 Result temp = allocator()->Allocate(); |
| 2872 __ mov(temp.reg(), Immediate(value)); |
| 2873 __ cvtsi2sd(xmm0, Operand(temp.reg())); |
| 2874 temp.Unuse(); |
| 2875 } |
| 2876 __ ucomisd(xmm1, xmm0); |
| 2877 // Jump to builtin for NaN. |
| 2878 not_number.Branch(parity_even, left_side); |
| 2879 left_side->Unuse(); |
| 2880 dest->true_target()->Branch(DoubleCondition(cc)); |
| 2881 dest->false_target()->Jump(); |
| 2882 not_number.Bind(left_side); |
| 2883 } |
| 2884 |
| 2885 // Setup and call the compare stub. |
| 2886 CompareStub stub(cc, strict, kCantBothBeNaN); |
| 2887 Result result = frame_->CallStub(&stub, left_side, right_side); |
| 2888 result.ToRegister(); |
| 2889 __ test(result.reg(), Operand(result.reg())); |
| 2890 result.Unuse(); |
| 2891 if (cc == equal) { |
| 2892 dest->Split(cc); |
| 2893 } else { |
| 2894 dest->true_target()->Branch(cc); |
| 2895 dest->false_target()->Jump(); |
| 2896 |
| 2897 // It is important for performance for this case to be at the end. |
| 2898 is_smi.Bind(left_side, right_side); |
| 2899 if (IsUnsafeSmi(right_side->handle())) { |
| 2900 right_side->ToRegister(); |
| 2901 __ cmp(left_reg, Operand(right_side->reg())); |
| 2902 } else { |
| 2903 __ cmp(Operand(left_reg), Immediate(right_side->handle())); |
| 2904 } |
| 2905 left_side->Unuse(); |
| 2906 right_side->Unuse(); |
| 2907 dest->Split(cc); |
| 2908 } |
| 2909 } |
| 2910 } |
| 2911 } |
| 2912 |
| 2913 |
2885 // Check that the comparison operand is a number. Jump to not_numbers jump | 2914 // Check that the comparison operand is a number. Jump to not_numbers jump |
2886 // target passing the left and right result if the operand is not a number. | 2915 // target passing the left and right result if the operand is not a number. |
2887 static void CheckComparisonOperand(MacroAssembler* masm_, | 2916 static void CheckComparisonOperand(MacroAssembler* masm_, |
2888 Result* operand, | 2917 Result* operand, |
2889 Result* left_side, | 2918 Result* left_side, |
2890 Result* right_side, | 2919 Result* right_side, |
2891 JumpTarget* not_numbers) { | 2920 JumpTarget* not_numbers) { |
2892 // Perform check if operand is not known to be a number. | 2921 // Perform check if operand is not known to be a number. |
2893 if (!operand->type_info().IsNumber()) { | 2922 if (!operand->type_info().IsNumber()) { |
2894 Label done; | 2923 Label done; |
(...skipping 10860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13755 masm.GetCode(&desc); | 13784 masm.GetCode(&desc); |
13756 // Call the function from C++. | 13785 // Call the function from C++. |
13757 return FUNCTION_CAST<MemCopyFunction>(buffer); | 13786 return FUNCTION_CAST<MemCopyFunction>(buffer); |
13758 } | 13787 } |
13759 | 13788 |
13760 #undef __ | 13789 #undef __ |
13761 | 13790 |
13762 } } // namespace v8::internal | 13791 } } // namespace v8::internal |
13763 | 13792 |
13764 #endif // V8_TARGET_ARCH_IA32 | 13793 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |