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 16 matching lines...) Expand all Loading... |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #if defined(V8_TARGET_ARCH_IA32) | 30 #if defined(V8_TARGET_ARCH_IA32) |
31 | 31 |
32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
33 #include "codegen-inl.h" | 33 #include "codegen-inl.h" |
34 #include "compiler.h" | 34 #include "compiler.h" |
35 #include "debug.h" | 35 #include "debug.h" |
36 #include "ic-inl.h" | 36 #include "ic-inl.h" |
37 #include "jsregexp.h" | |
38 #include "parser.h" | 37 #include "parser.h" |
39 #include "regexp-macro-assembler.h" | 38 #include "regexp-macro-assembler.h" |
40 #include "regexp-stack.h" | |
41 #include "register-allocator-inl.h" | 39 #include "register-allocator-inl.h" |
42 #include "runtime.h" | |
43 #include "scopes.h" | 40 #include "scopes.h" |
44 #include "virtual-frame-inl.h" | 41 #include "virtual-frame-inl.h" |
45 | 42 |
46 namespace v8 { | 43 namespace v8 { |
47 namespace internal { | 44 namespace internal { |
48 | 45 |
49 #define __ ACCESS_MASM(masm) | 46 #define __ ACCESS_MASM(masm) |
50 | 47 |
51 // ------------------------------------------------------------------------- | 48 // ------------------------------------------------------------------------- |
52 // Platform-specific FrameRegisterState functions. | 49 // Platform-specific FrameRegisterState functions. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 } | 133 } |
137 | 134 |
138 | 135 |
139 CodeGenState::~CodeGenState() { | 136 CodeGenState::~CodeGenState() { |
140 ASSERT(owner_->state() == this); | 137 ASSERT(owner_->state() == this); |
141 owner_->set_state(previous_); | 138 owner_->set_state(previous_); |
142 } | 139 } |
143 | 140 |
144 | 141 |
145 // ------------------------------------------------------------------------- | 142 // ------------------------------------------------------------------------- |
146 // CodeGenerator implementation | 143 // CodeGenerator implementation. |
147 | 144 |
148 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 145 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
149 : deferred_(8), | 146 : deferred_(8), |
150 masm_(masm), | 147 masm_(masm), |
151 info_(NULL), | 148 info_(NULL), |
152 frame_(NULL), | 149 frame_(NULL), |
153 allocator_(NULL), | 150 allocator_(NULL), |
154 state_(NULL), | 151 state_(NULL), |
155 loop_nesting_(0), | 152 loop_nesting_(0), |
156 in_safe_int32_mode_(false), | 153 in_safe_int32_mode_(false), |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 // compile an artificial return statement just above, and (b) there | 364 // compile an artificial return statement just above, and (b) there |
368 // are return statements in the body but (c) they are all shadowed. | 365 // are return statements in the body but (c) they are all shadowed. |
369 Result return_value; | 366 Result return_value; |
370 function_return_.Bind(&return_value); | 367 function_return_.Bind(&return_value); |
371 GenerateReturnSequence(&return_value); | 368 GenerateReturnSequence(&return_value); |
372 } | 369 } |
373 } | 370 } |
374 } | 371 } |
375 | 372 |
376 // Adjust for function-level loop nesting. | 373 // Adjust for function-level loop nesting. |
377 ASSERT_EQ(info->loop_nesting(), loop_nesting_); | 374 ASSERT_EQ(loop_nesting_, info->loop_nesting()); |
378 loop_nesting_ = 0; | 375 loop_nesting_ = 0; |
379 | 376 |
380 // Code generation state must be reset. | 377 // Code generation state must be reset. |
381 ASSERT(state_ == NULL); | 378 ASSERT(state_ == NULL); |
382 ASSERT(loop_nesting() == 0); | |
383 ASSERT(!function_return_is_shadowed_); | 379 ASSERT(!function_return_is_shadowed_); |
384 function_return_.Unuse(); | 380 function_return_.Unuse(); |
385 DeleteFrame(); | 381 DeleteFrame(); |
386 | 382 |
387 // Process any deferred code using the register allocator. | 383 // Process any deferred code using the register allocator. |
388 if (!HasStackOverflow()) { | 384 if (!HasStackOverflow()) { |
389 HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); | 385 HistogramTimerScope deferred_timer(&Counters::deferred_code_generation); |
390 JumpTarget::set_compiling_deferred_code(true); | 386 JumpTarget::set_compiling_deferred_code(true); |
391 ProcessDeferred(); | 387 ProcessDeferred(); |
392 JumpTarget::set_compiling_deferred_code(false); | 388 JumpTarget::set_compiling_deferred_code(false); |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
639 done.Jump(); | 635 done.Jump(); |
640 | 636 |
641 if (unsafe_bailout.is_linked()) { | 637 if (unsafe_bailout.is_linked()) { |
642 unsafe_bailout.Bind(); | 638 unsafe_bailout.Bind(); |
643 LoadWithSafeInt32ModeDisabled(expr); | 639 LoadWithSafeInt32ModeDisabled(expr); |
644 } | 640 } |
645 done.Bind(); | 641 done.Bind(); |
646 } else { | 642 } else { |
647 JumpTarget true_target; | 643 JumpTarget true_target; |
648 JumpTarget false_target; | 644 JumpTarget false_target; |
649 | |
650 ControlDestination dest(&true_target, &false_target, true); | 645 ControlDestination dest(&true_target, &false_target, true); |
651 LoadCondition(expr, &dest, false); | 646 LoadCondition(expr, &dest, false); |
652 | 647 |
653 if (dest.false_was_fall_through()) { | 648 if (dest.false_was_fall_through()) { |
654 // The false target was just bound. | 649 // The false target was just bound. |
655 JumpTarget loaded; | 650 JumpTarget loaded; |
656 frame_->Push(Factory::false_value()); | 651 frame_->Push(Factory::false_value()); |
657 // There may be dangling jumps to the true target. | 652 // There may be dangling jumps to the true target. |
658 if (true_target.is_linked()) { | 653 if (true_target.is_linked()) { |
659 loaded.Jump(); | 654 loaded.Jump(); |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
777 frame_->Push(&result); | 772 frame_->Push(&result); |
778 } | 773 } |
779 | 774 |
780 Variable* arguments = scope()->arguments()->var(); | 775 Variable* arguments = scope()->arguments()->var(); |
781 Variable* shadow = scope()->arguments_shadow()->var(); | 776 Variable* shadow = scope()->arguments_shadow()->var(); |
782 ASSERT(arguments != NULL && arguments->slot() != NULL); | 777 ASSERT(arguments != NULL && arguments->slot() != NULL); |
783 ASSERT(shadow != NULL && shadow->slot() != NULL); | 778 ASSERT(shadow != NULL && shadow->slot() != NULL); |
784 JumpTarget done; | 779 JumpTarget done; |
785 bool skip_arguments = false; | 780 bool skip_arguments = false; |
786 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 781 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { |
787 // We have to skip storing into the arguments slot if it has already | 782 // We have to skip storing into the arguments slot if it has |
788 // been written to. This can happen if the a function has a local | 783 // already been written to. This can happen if the a function |
789 // variable named 'arguments'. | 784 // has a local variable named 'arguments'. |
790 LoadFromSlot(arguments->slot(), NOT_INSIDE_TYPEOF); | 785 LoadFromSlot(arguments->slot(), NOT_INSIDE_TYPEOF); |
791 Result probe = frame_->Pop(); | 786 Result probe = frame_->Pop(); |
792 if (probe.is_constant()) { | 787 if (probe.is_constant()) { |
793 // We have to skip updating the arguments object if it has | 788 // We have to skip updating the arguments object if it has |
794 // been assigned a proper value. | 789 // been assigned a proper value. |
795 skip_arguments = !probe.handle()->IsTheHole(); | 790 skip_arguments = !probe.handle()->IsTheHole(); |
796 } else { | 791 } else { |
797 __ cmp(Operand(probe.reg()), Immediate(Factory::the_hole_value())); | 792 __ cmp(Operand(probe.reg()), Immediate(Factory::the_hole_value())); |
798 probe.Unuse(); | 793 probe.Unuse(); |
799 done.Branch(not_equal); | 794 done.Branch(not_equal); |
(...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1427 unsigned int unsigned_left = left; | 1422 unsigned int unsigned_left = left; |
1428 if (left < 0) { | 1423 if (left < 0) { |
1429 // Perform arithmetic shift of a negative number by | 1424 // Perform arithmetic shift of a negative number by |
1430 // complementing number, logical shifting, complementing again. | 1425 // complementing number, logical shifting, complementing again. |
1431 unsigned_left = ~unsigned_left; | 1426 unsigned_left = ~unsigned_left; |
1432 unsigned_left >>= shift_amount; | 1427 unsigned_left >>= shift_amount; |
1433 unsigned_left = ~unsigned_left; | 1428 unsigned_left = ~unsigned_left; |
1434 } else { | 1429 } else { |
1435 unsigned_left >>= shift_amount; | 1430 unsigned_left >>= shift_amount; |
1436 } | 1431 } |
1437 ASSERT(Smi::IsValid(unsigned_left)); // Converted to signed. | 1432 ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left))); |
1438 answer_object = Smi::FromInt(unsigned_left); // Converted to signed. | 1433 answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left)); |
1439 break; | 1434 break; |
1440 } | 1435 } |
1441 default: | 1436 default: |
1442 UNREACHABLE(); | 1437 UNREACHABLE(); |
1443 break; | 1438 break; |
1444 } | 1439 } |
1445 if (answer_object == Heap::undefined_value()) { | 1440 if (answer_object == Heap::undefined_value()) { |
1446 return false; | 1441 return false; |
1447 } | 1442 } |
1448 frame_->Push(Handle<Object>(answer_object)); | 1443 frame_->Push(Handle<Object>(answer_object)); |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1912 Token::Value op_; | 1907 Token::Value op_; |
1913 Register dst_; | 1908 Register dst_; |
1914 TypeInfo type_info_; | 1909 TypeInfo type_info_; |
1915 Smi* value_; | 1910 Smi* value_; |
1916 Register src_; | 1911 Register src_; |
1917 OverwriteMode overwrite_mode_; | 1912 OverwriteMode overwrite_mode_; |
1918 }; | 1913 }; |
1919 | 1914 |
1920 | 1915 |
1921 void DeferredInlineSmiOperationReversed::Generate() { | 1916 void DeferredInlineSmiOperationReversed::Generate() { |
1922 GenericBinaryOpStub igostub( | 1917 GenericBinaryOpStub stub( |
1923 op_, | 1918 op_, |
1924 overwrite_mode_, | 1919 overwrite_mode_, |
1925 NO_SMI_CODE_IN_STUB, | 1920 NO_SMI_CODE_IN_STUB, |
1926 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); | 1921 TypeInfo::Combine(TypeInfo::Smi(), type_info_)); |
1927 igostub.GenerateCall(masm_, value_, src_); | 1922 stub.GenerateCall(masm_, value_, src_); |
1928 if (!dst_.is(eax)) __ mov(dst_, eax); | 1923 if (!dst_.is(eax)) __ mov(dst_, eax); |
1929 } | 1924 } |
1930 | 1925 |
1931 | 1926 |
1932 // The result of src + value is in dst. It either overflowed or was not | 1927 // The result of src + value is in dst. It either overflowed or was not |
1933 // smi tagged. Undo the speculative addition and call the appropriate | 1928 // smi tagged. Undo the speculative addition and call the appropriate |
1934 // specialized stub for add. The result is left in dst. | 1929 // specialized stub for add. The result is left in dst. |
1935 class DeferredInlineSmiAdd: public DeferredCode { | 1930 class DeferredInlineSmiAdd: public DeferredCode { |
1936 public: | 1931 public: |
1937 DeferredInlineSmiAdd(Register dst, | 1932 DeferredInlineSmiAdd(Register dst, |
(...skipping 479 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2417 if (int_value == 1) { | 2412 if (int_value == 1) { |
2418 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); | 2413 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); |
2419 } else { | 2414 } else { |
2420 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); | 2415 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); |
2421 } | 2416 } |
2422 deferred->BindExit(); | 2417 deferred->BindExit(); |
2423 answer = *operand; | 2418 answer = *operand; |
2424 break; | 2419 break; |
2425 } | 2420 } |
2426 // Fall through if we did not find a power of 2 on the right hand side! | 2421 // Fall through if we did not find a power of 2 on the right hand side! |
| 2422 // The next case must be the default. |
2427 | 2423 |
2428 default: { | 2424 default: { |
2429 Result constant_operand(value); | 2425 Result constant_operand(value); |
2430 if (reversed) { | 2426 if (reversed) { |
2431 answer = LikelySmiBinaryOperation(expr, &constant_operand, operand, | 2427 answer = LikelySmiBinaryOperation(expr, &constant_operand, operand, |
2432 overwrite_mode); | 2428 overwrite_mode); |
2433 } else { | 2429 } else { |
2434 answer = LikelySmiBinaryOperation(expr, operand, &constant_operand, | 2430 answer = LikelySmiBinaryOperation(expr, operand, &constant_operand, |
2435 overwrite_mode); | 2431 overwrite_mode); |
2436 } | 2432 } |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2669 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), | 2665 __ cmp(FieldOperand(left_side.reg(), String::kLengthOffset), |
2670 Immediate(Smi::FromInt(1))); | 2666 Immediate(Smi::FromInt(1))); |
2671 } | 2667 } |
2672 __ bind(&comparison_done); | 2668 __ bind(&comparison_done); |
2673 left_side.Unuse(); | 2669 left_side.Unuse(); |
2674 right_side.Unuse(); | 2670 right_side.Unuse(); |
2675 dest->Split(cc); | 2671 dest->Split(cc); |
2676 } | 2672 } |
2677 } else { | 2673 } else { |
2678 // Neither side is a constant Smi, constant 1-char string or constant null. | 2674 // Neither side is a constant Smi, constant 1-char string or constant null. |
2679 // If either side is a non-smi constant, or known to be a heap number skip | 2675 // If either side is a non-smi constant, or known to be a heap number, |
2680 // the smi check. | 2676 // skip the smi check. |
2681 bool known_non_smi = | 2677 bool known_non_smi = |
2682 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 2678 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
2683 (right_side.is_constant() && !right_side.handle()->IsSmi()) || | 2679 (right_side.is_constant() && !right_side.handle()->IsSmi()) || |
2684 left_side.type_info().IsDouble() || | 2680 left_side.type_info().IsDouble() || |
2685 right_side.type_info().IsDouble(); | 2681 right_side.type_info().IsDouble(); |
| 2682 |
2686 NaNInformation nan_info = | 2683 NaNInformation nan_info = |
2687 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? | 2684 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? |
2688 kBothCouldBeNaN : | 2685 kBothCouldBeNaN : |
2689 kCantBothBeNaN; | 2686 kCantBothBeNaN; |
2690 | 2687 |
2691 // Inline number comparison handling any combination of smi's and heap | 2688 // Inline number comparison handling any combination of smi's and heap |
2692 // numbers if: | 2689 // numbers if: |
2693 // code is in a loop | 2690 // code is in a loop |
2694 // the compare operation is different from equal | 2691 // the compare operation is different from equal |
2695 // compare is not a for-loop comparison | 2692 // compare is not a for-loop comparison |
2696 // The reason for excluding equal is that it will most likely be done | 2693 // The reason for excluding equal is that it will most likely be done |
2697 // with smi's (not heap numbers) and the code to comparing smi's is inlined | 2694 // with smi's (not heap numbers) and the code to comparing smi's is inlined |
2698 // separately. The same reason applies for for-loop comparison which will | 2695 // separately. The same reason applies for for-loop comparison which will |
2699 // also most likely be smi comparisons. | 2696 // also most likely be smi comparisons. |
2700 bool is_loop_condition = (node->AsExpression() != NULL) | 2697 bool is_loop_condition = (node->AsExpression() != NULL) |
2701 && node->AsExpression()->is_loop_condition(); | 2698 && node->AsExpression()->is_loop_condition(); |
2702 bool inline_number_compare = | 2699 bool inline_number_compare = |
2703 loop_nesting() > 0 && cc != equal && !is_loop_condition; | 2700 loop_nesting() > 0 && cc != equal && !is_loop_condition; |
2704 | 2701 |
2705 // Left and right needed in registers for the following code. | 2702 // Left and right needed in registers for the following code. |
2706 left_side.ToRegister(); | 2703 left_side.ToRegister(); |
2707 right_side.ToRegister(); | 2704 right_side.ToRegister(); |
2708 | 2705 |
2709 if (known_non_smi) { | 2706 if (known_non_smi) { |
2710 // Inline the equality check if both operands can't be a NaN. If both | 2707 // Inlined equality check: |
2711 // objects are the same they are equal. | 2708 // If at least one of the objects is not NaN, then if the objects |
| 2709 // are identical, they are equal. |
2712 if (nan_info == kCantBothBeNaN && cc == equal) { | 2710 if (nan_info == kCantBothBeNaN && cc == equal) { |
2713 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2711 __ cmp(left_side.reg(), Operand(right_side.reg())); |
2714 dest->true_target()->Branch(equal); | 2712 dest->true_target()->Branch(equal); |
2715 } | 2713 } |
2716 | 2714 |
2717 // Inline number comparison. | 2715 // Inlined number comparison: |
2718 if (inline_number_compare) { | 2716 if (inline_number_compare) { |
2719 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | 2717 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
2720 } | 2718 } |
2721 | 2719 |
2722 // End of in-line compare, call out to the compare stub. Don't include | 2720 // End of in-line compare, call out to the compare stub. Don't include |
2723 // number comparison in the stub if it was inlined. | 2721 // number comparison in the stub if it was inlined. |
2724 CompareStub stub(cc, strict, nan_info, !inline_number_compare); | 2722 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
2725 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2723 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2726 __ test(answer.reg(), Operand(answer.reg())); | 2724 __ test(answer.reg(), Operand(answer.reg())); |
2727 answer.Unuse(); | 2725 answer.Unuse(); |
(...skipping 17 matching lines...) Expand all Loading... |
2745 temp.Unuse(); | 2743 temp.Unuse(); |
2746 is_smi.Branch(zero, taken); | 2744 is_smi.Branch(zero, taken); |
2747 | 2745 |
2748 // Inline the equality check if both operands can't be a NaN. If both | 2746 // Inline the equality check if both operands can't be a NaN. If both |
2749 // objects are the same they are equal. | 2747 // objects are the same they are equal. |
2750 if (nan_info == kCantBothBeNaN && cc == equal) { | 2748 if (nan_info == kCantBothBeNaN && cc == equal) { |
2751 __ cmp(left_side.reg(), Operand(right_side.reg())); | 2749 __ cmp(left_side.reg(), Operand(right_side.reg())); |
2752 dest->true_target()->Branch(equal); | 2750 dest->true_target()->Branch(equal); |
2753 } | 2751 } |
2754 | 2752 |
2755 // Inline number comparison. | 2753 // Inlined number comparison: |
2756 if (inline_number_compare) { | 2754 if (inline_number_compare) { |
2757 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | 2755 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
2758 } | 2756 } |
2759 | 2757 |
2760 // End of in-line compare, call out to the compare stub. Don't include | 2758 // End of in-line compare, call out to the compare stub. Don't include |
2761 // number comparison in the stub if it was inlined. | 2759 // number comparison in the stub if it was inlined. |
2762 CompareStub stub(cc, strict, nan_info, !inline_number_compare); | 2760 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
2763 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2761 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
2764 __ test(answer.reg(), Operand(answer.reg())); | 2762 __ test(answer.reg(), Operand(answer.reg())); |
2765 answer.Unuse(); | 2763 answer.Unuse(); |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2963 __ jmp(&done); | 2961 __ jmp(&done); |
2964 } | 2962 } |
2965 __ bind(&done); | 2963 __ bind(&done); |
2966 } | 2964 } |
2967 | 2965 |
2968 | 2966 |
2969 // Load a comparison operand into into a XMM register. Jump to not_numbers jump | 2967 // Load a comparison operand into into a XMM register. Jump to not_numbers jump |
2970 // target passing the left and right result if the operand is not a number. | 2968 // target passing the left and right result if the operand is not a number. |
2971 static void LoadComparisonOperandSSE2(MacroAssembler* masm_, | 2969 static void LoadComparisonOperandSSE2(MacroAssembler* masm_, |
2972 Result* operand, | 2970 Result* operand, |
2973 XMMRegister reg, | 2971 XMMRegister xmm_reg, |
2974 Result* left_side, | 2972 Result* left_side, |
2975 Result* right_side, | 2973 Result* right_side, |
2976 JumpTarget* not_numbers) { | 2974 JumpTarget* not_numbers) { |
2977 Label done; | 2975 Label done; |
2978 if (operand->type_info().IsDouble()) { | 2976 if (operand->type_info().IsDouble()) { |
2979 // Operand is known to be a heap number, just load it. | 2977 // Operand is known to be a heap number, just load it. |
2980 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | 2978 __ movdbl(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
2981 } else if (operand->type_info().IsSmi()) { | 2979 } else if (operand->type_info().IsSmi()) { |
2982 // Operand is known to be a smi. Convert it to double and keep the original | 2980 // Operand is known to be a smi. Convert it to double and keep the original |
2983 // smi. | 2981 // smi. |
2984 __ SmiUntag(operand->reg()); | 2982 __ SmiUntag(operand->reg()); |
2985 __ cvtsi2sd(reg, Operand(operand->reg())); | 2983 __ cvtsi2sd(xmm_reg, Operand(operand->reg())); |
2986 __ SmiTag(operand->reg()); | 2984 __ SmiTag(operand->reg()); |
2987 } else { | 2985 } else { |
2988 // Operand type not known, check for smi or heap number. | 2986 // Operand type not known, check for smi or heap number. |
2989 Label smi; | 2987 Label smi; |
2990 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2988 __ test(operand->reg(), Immediate(kSmiTagMask)); |
2991 __ j(zero, &smi); | 2989 __ j(zero, &smi); |
2992 if (!operand->type_info().IsNumber()) { | 2990 if (!operand->type_info().IsNumber()) { |
2993 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), | 2991 __ cmp(FieldOperand(operand->reg(), HeapObject::kMapOffset), |
2994 Immediate(Factory::heap_number_map())); | 2992 Immediate(Factory::heap_number_map())); |
2995 not_numbers->Branch(not_equal, left_side, right_side, taken); | 2993 not_numbers->Branch(not_equal, left_side, right_side, taken); |
2996 } | 2994 } |
2997 __ movdbl(reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); | 2995 __ movdbl(xmm_reg, FieldOperand(operand->reg(), HeapNumber::kValueOffset)); |
2998 __ jmp(&done); | 2996 __ jmp(&done); |
2999 | 2997 |
3000 __ bind(&smi); | 2998 __ bind(&smi); |
3001 // Comvert smi to float and keep the original smi. | 2999 // Comvert smi to float and keep the original smi. |
3002 __ SmiUntag(operand->reg()); | 3000 __ SmiUntag(operand->reg()); |
3003 __ cvtsi2sd(reg, Operand(operand->reg())); | 3001 __ cvtsi2sd(xmm_reg, Operand(operand->reg())); |
3004 __ SmiTag(operand->reg()); | 3002 __ SmiTag(operand->reg()); |
3005 __ jmp(&done); | 3003 __ jmp(&done); |
3006 } | 3004 } |
3007 __ bind(&done); | 3005 __ bind(&done); |
3008 } | 3006 } |
3009 | 3007 |
3010 | 3008 |
3011 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, | 3009 void CodeGenerator::GenerateInlineNumberComparison(Result* left_side, |
3012 Result* right_side, | 3010 Result* right_side, |
3013 Condition cc, | 3011 Condition cc, |
(...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3590 // reference to eax. This is safe because the current frame does not | 3588 // reference to eax. This is safe because the current frame does not |
3591 // contain a reference to eax (it is prepared for the return by spilling | 3589 // contain a reference to eax (it is prepared for the return by spilling |
3592 // all registers). | 3590 // all registers). |
3593 if (FLAG_trace) { | 3591 if (FLAG_trace) { |
3594 frame_->Push(return_value); | 3592 frame_->Push(return_value); |
3595 *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1); | 3593 *return_value = frame_->CallRuntime(Runtime::kTraceExit, 1); |
3596 } | 3594 } |
3597 return_value->ToRegister(eax); | 3595 return_value->ToRegister(eax); |
3598 | 3596 |
3599 // Add a label for checking the size of the code used for returning. | 3597 // Add a label for checking the size of the code used for returning. |
| 3598 #ifdef DEBUG |
3600 Label check_exit_codesize; | 3599 Label check_exit_codesize; |
3601 masm_->bind(&check_exit_codesize); | 3600 masm_->bind(&check_exit_codesize); |
| 3601 #endif |
3602 | 3602 |
3603 // Leave the frame and return popping the arguments and the | 3603 // Leave the frame and return popping the arguments and the |
3604 // receiver. | 3604 // receiver. |
3605 frame_->Exit(); | 3605 frame_->Exit(); |
3606 masm_->ret((scope()->num_parameters() + 1) * kPointerSize); | 3606 masm_->ret((scope()->num_parameters() + 1) * kPointerSize); |
3607 DeleteFrame(); | 3607 DeleteFrame(); |
3608 | 3608 |
3609 #ifdef ENABLE_DEBUGGER_SUPPORT | 3609 #ifdef ENABLE_DEBUGGER_SUPPORT |
3610 // Check that the size of the code used for returning matches what is | 3610 // Check that the size of the code used for returning matches what is |
3611 // expected by the debugger. | 3611 // expected by the debugger. |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3712 } | 3712 } |
3713 // Drop the switch value. | 3713 // Drop the switch value. |
3714 frame_->Drop(); | 3714 frame_->Drop(); |
3715 if (default_clause != NULL) { | 3715 if (default_clause != NULL) { |
3716 default_clause->body_target()->Jump(); | 3716 default_clause->body_target()->Jump(); |
3717 } else { | 3717 } else { |
3718 node->break_target()->Jump(); | 3718 node->break_target()->Jump(); |
3719 } | 3719 } |
3720 } | 3720 } |
3721 | 3721 |
3722 | |
3723 // The last instruction emitted was a jump, either to the default | 3722 // The last instruction emitted was a jump, either to the default |
3724 // clause or the break target, or else to a case body from the loop | 3723 // clause or the break target, or else to a case body from the loop |
3725 // that compiles the tests. | 3724 // that compiles the tests. |
3726 ASSERT(!has_valid_frame()); | 3725 ASSERT(!has_valid_frame()); |
3727 // Compile case bodies as needed. | 3726 // Compile case bodies as needed. |
3728 for (int i = 0; i < length; i++) { | 3727 for (int i = 0; i < length; i++) { |
3729 CaseClause* clause = cases->at(i); | 3728 CaseClause* clause = cases->at(i); |
3730 | 3729 |
3731 // There are two ways to reach the body: from the corresponding | 3730 // There are two ways to reach the body: from the corresponding |
3732 // test or as the fall through of the previous body. | 3731 // test or as the fall through of the previous body. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3800 body.Bind(); | 3799 body.Bind(); |
3801 break; | 3800 break; |
3802 } | 3801 } |
3803 | 3802 |
3804 CheckStack(); // TODO(1222600): ignore if body contains calls. | 3803 CheckStack(); // TODO(1222600): ignore if body contains calls. |
3805 Visit(node->body()); | 3804 Visit(node->body()); |
3806 | 3805 |
3807 // Compile the test. | 3806 // Compile the test. |
3808 switch (info) { | 3807 switch (info) { |
3809 case ALWAYS_TRUE: | 3808 case ALWAYS_TRUE: |
3810 // If control flow can fall off the end of the body, jump back to | 3809 // If control flow can fall off the end of the body, jump back |
3811 // the top and bind the break target at the exit. | 3810 // to the top and bind the break target at the exit. |
3812 if (has_valid_frame()) { | 3811 if (has_valid_frame()) { |
3813 node->continue_target()->Jump(); | 3812 node->continue_target()->Jump(); |
3814 } | 3813 } |
3815 if (node->break_target()->is_linked()) { | 3814 if (node->break_target()->is_linked()) { |
3816 node->break_target()->Bind(); | 3815 node->break_target()->Bind(); |
3817 } | 3816 } |
3818 break; | 3817 break; |
3819 case ALWAYS_FALSE: | 3818 case ALWAYS_FALSE: |
3820 // We may have had continues or breaks in the body. | 3819 // We may have had continues or breaks in the body. |
3821 if (node->continue_target()->is_linked()) { | 3820 if (node->continue_target()->is_linked()) { |
(...skipping 15 matching lines...) Expand all Loading... |
3837 ControlDestination dest(&body, node->break_target(), false); | 3836 ControlDestination dest(&body, node->break_target(), false); |
3838 LoadCondition(node->cond(), &dest, true); | 3837 LoadCondition(node->cond(), &dest, true); |
3839 } | 3838 } |
3840 if (node->break_target()->is_linked()) { | 3839 if (node->break_target()->is_linked()) { |
3841 node->break_target()->Bind(); | 3840 node->break_target()->Bind(); |
3842 } | 3841 } |
3843 break; | 3842 break; |
3844 } | 3843 } |
3845 | 3844 |
3846 DecrementLoopNesting(); | 3845 DecrementLoopNesting(); |
| 3846 node->continue_target()->Unuse(); |
| 3847 node->break_target()->Unuse(); |
3847 } | 3848 } |
3848 | 3849 |
3849 | 3850 |
3850 void CodeGenerator::VisitWhileStatement(WhileStatement* node) { | 3851 void CodeGenerator::VisitWhileStatement(WhileStatement* node) { |
3851 ASSERT(!in_spilled_code()); | 3852 ASSERT(!in_spilled_code()); |
3852 Comment cmnt(masm_, "[ WhileStatement"); | 3853 Comment cmnt(masm_, "[ WhileStatement"); |
3853 CodeForStatementPosition(node); | 3854 CodeForStatementPosition(node); |
3854 | 3855 |
3855 // If the condition is always false and has no side effects, we do not | 3856 // If the condition is always false and has no side effects, we do not |
3856 // need to compile anything. | 3857 // need to compile anything. |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3921 // necessary. | 3922 // necessary. |
3922 switch (info) { | 3923 switch (info) { |
3923 case ALWAYS_TRUE: | 3924 case ALWAYS_TRUE: |
3924 // The loop body has been labeled with the continue target. | 3925 // The loop body has been labeled with the continue target. |
3925 if (has_valid_frame()) { | 3926 if (has_valid_frame()) { |
3926 node->continue_target()->Jump(); | 3927 node->continue_target()->Jump(); |
3927 } | 3928 } |
3928 break; | 3929 break; |
3929 case DONT_KNOW: | 3930 case DONT_KNOW: |
3930 if (test_at_bottom) { | 3931 if (test_at_bottom) { |
3931 // If we have chosen to recompile the test at the bottom, then | 3932 // If we have chosen to recompile the test at the bottom, |
3932 // it is the continue target. | 3933 // then it is the continue target. |
3933 if (node->continue_target()->is_linked()) { | 3934 if (node->continue_target()->is_linked()) { |
3934 node->continue_target()->Bind(); | 3935 node->continue_target()->Bind(); |
3935 } | 3936 } |
3936 if (has_valid_frame()) { | 3937 if (has_valid_frame()) { |
3937 // The break target is the fall-through (body is a backward | 3938 // The break target is the fall-through (body is a backward |
3938 // jump from here and thus an invalid fall-through). | 3939 // jump from here and thus an invalid fall-through). |
3939 ControlDestination dest(&body, node->break_target(), false); | 3940 ControlDestination dest(&body, node->break_target(), false); |
3940 LoadCondition(node->cond(), &dest, true); | 3941 LoadCondition(node->cond(), &dest, true); |
3941 } | 3942 } |
3942 } else { | 3943 } else { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4038 // We are not recompiling the test at the bottom and there is no | 4039 // We are not recompiling the test at the bottom and there is no |
4039 // update expression. | 4040 // update expression. |
4040 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); | 4041 node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL); |
4041 node->continue_target()->Bind(); | 4042 node->continue_target()->Bind(); |
4042 } else { | 4043 } else { |
4043 // We are not recompiling the test at the bottom and there is an | 4044 // We are not recompiling the test at the bottom and there is an |
4044 // update expression. | 4045 // update expression. |
4045 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | 4046 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
4046 loop.Bind(); | 4047 loop.Bind(); |
4047 } | 4048 } |
| 4049 |
4048 // Compile the test with the body as the true target and preferred | 4050 // Compile the test with the body as the true target and preferred |
4049 // fall-through and with the break target as the false target. | 4051 // fall-through and with the break target as the false target. |
4050 ControlDestination dest(&body, node->break_target(), true); | 4052 ControlDestination dest(&body, node->break_target(), true); |
4051 LoadCondition(node->cond(), &dest, true); | 4053 LoadCondition(node->cond(), &dest, true); |
4052 | 4054 |
4053 if (dest.false_was_fall_through()) { | 4055 if (dest.false_was_fall_through()) { |
4054 // If we got the break target as fall-through, the test may have | 4056 // If we got the break target as fall-through, the test may have |
4055 // been unconditionally false (if there are no jumps to the | 4057 // been unconditionally false (if there are no jumps to the |
4056 // body). | 4058 // body). |
4057 if (!body.is_linked()) { | 4059 if (!body.is_linked()) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4147 loop.Jump(); | 4149 loop.Jump(); |
4148 } | 4150 } |
4149 } | 4151 } |
4150 } | 4152 } |
4151 break; | 4153 break; |
4152 case ALWAYS_FALSE: | 4154 case ALWAYS_FALSE: |
4153 UNREACHABLE(); | 4155 UNREACHABLE(); |
4154 break; | 4156 break; |
4155 } | 4157 } |
4156 | 4158 |
4157 // The break target may be already bound (by the condition), or | 4159 // The break target may be already bound (by the condition), or there |
4158 // there may not be a valid frame. Bind it only if needed. | 4160 // may not be a valid frame. Bind it only if needed. |
4159 if (node->break_target()->is_linked()) { | 4161 if (node->break_target()->is_linked()) { |
4160 node->break_target()->Bind(); | 4162 node->break_target()->Bind(); |
4161 } | 4163 } |
4162 DecrementLoopNesting(); | 4164 DecrementLoopNesting(); |
4163 } | 4165 } |
4164 | 4166 |
4165 | 4167 |
4166 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 4168 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
4167 ASSERT(!in_spilled_code()); | 4169 ASSERT(!in_spilled_code()); |
4168 VirtualFrame::SpilledScope spilled_scope; | 4170 VirtualFrame::SpilledScope spilled_scope; |
(...skipping 9615 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13784 masm.GetCode(&desc); | 13786 masm.GetCode(&desc); |
13785 // Call the function from C++. | 13787 // Call the function from C++. |
13786 return FUNCTION_CAST<MemCopyFunction>(buffer); | 13788 return FUNCTION_CAST<MemCopyFunction>(buffer); |
13787 } | 13789 } |
13788 | 13790 |
13789 #undef __ | 13791 #undef __ |
13790 | 13792 |
13791 } } // namespace v8::internal | 13793 } } // namespace v8::internal |
13792 | 13794 |
13793 #endif // V8_TARGET_ARCH_IA32 | 13795 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |