| 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 |