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 |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_X64) |
| 31 |
30 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
31 #include "codegen-inl.h" | 33 #include "codegen-inl.h" |
32 #include "compiler.h" | 34 #include "compiler.h" |
33 #include "debug.h" | 35 #include "debug.h" |
34 #include "ic-inl.h" | 36 #include "ic-inl.h" |
35 #include "parser.h" | 37 #include "parser.h" |
36 #include "regexp-macro-assembler.h" | 38 #include "regexp-macro-assembler.h" |
37 #include "register-allocator-inl.h" | 39 #include "register-allocator-inl.h" |
38 #include "scopes.h" | 40 #include "scopes.h" |
39 #include "virtual-frame-inl.h" | 41 #include "virtual-frame-inl.h" |
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
671 private: | 673 private: |
672 Register value_; | 674 Register value_; |
673 Register key_; | 675 Register key_; |
674 Register receiver_; | 676 Register receiver_; |
675 Label patch_site_; | 677 Label patch_site_; |
676 }; | 678 }; |
677 | 679 |
678 | 680 |
679 void DeferredReferenceSetKeyedValue::Generate() { | 681 void DeferredReferenceSetKeyedValue::Generate() { |
680 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 682 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); |
681 // Push receiver and key arguments on the stack. | 683 // Move value, receiver, and key to registers rax, rdx, and rcx, as |
682 __ push(receiver_); | 684 // the IC stub expects. |
683 __ push(key_); | 685 // Move value to rax, using xchg if the receiver or key is in rax. |
684 // Move value argument to eax as expected by the IC stub. | 686 if (!value_.is(rax)) { |
685 if (!value_.is(rax)) __ movq(rax, value_); | 687 if (!receiver_.is(rax) && !key_.is(rax)) { |
| 688 __ movq(rax, value_); |
| 689 } else { |
| 690 __ xchg(rax, value_); |
| 691 // Update receiver_ and key_ if they are affected by the swap. |
| 692 if (receiver_.is(rax)) { |
| 693 receiver_ = value_; |
| 694 } else if (receiver_.is(value_)) { |
| 695 receiver_ = rax; |
| 696 } |
| 697 if (key_.is(rax)) { |
| 698 key_ = value_; |
| 699 } else if (key_.is(value_)) { |
| 700 key_ = rax; |
| 701 } |
| 702 } |
| 703 } |
| 704 // Value is now in rax. Its original location is remembered in value_, |
| 705 // and the value is restored to value_ before returning. |
| 706 // The variables receiver_ and key_ are not preserved. |
| 707 // Move receiver and key to rdx and rcx, swapping if necessary. |
| 708 if (receiver_.is(rdx)) { |
| 709 if (!key_.is(rcx)) { |
| 710 __ movq(rcx, key_); |
| 711 } // Else everything is already in the right place. |
| 712 } else if (receiver_.is(rcx)) { |
| 713 if (key_.is(rdx)) { |
| 714 __ xchg(rcx, rdx); |
| 715 } else if (key_.is(rcx)) { |
| 716 __ movq(rdx, receiver_); |
| 717 } else { |
| 718 __ movq(rdx, receiver_); |
| 719 __ movq(rcx, key_); |
| 720 } |
| 721 } else if (key_.is(rcx)) { |
| 722 __ movq(rdx, receiver_); |
| 723 } else { |
| 724 __ movq(rcx, key_); |
| 725 __ movq(rdx, receiver_); |
| 726 } |
| 727 |
686 // Call the IC stub. | 728 // Call the IC stub. |
687 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 729 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
688 __ Call(ic, RelocInfo::CODE_TARGET); | 730 __ Call(ic, RelocInfo::CODE_TARGET); |
689 // The delta from the start of the map-compare instructions (initial movq) | 731 // The delta from the start of the map-compare instructions (initial movq) |
690 // to the test instruction. We use masm_-> directly here instead of the | 732 // to the test instruction. We use masm_-> directly here instead of the |
691 // __ macro because the macro sometimes uses macro expansion to turn | 733 // __ macro because the macro sometimes uses macro expansion to turn |
692 // into something that can't return a value. This is encountered | 734 // into something that can't return a value. This is encountered |
693 // when doing generated code coverage tests. | 735 // when doing generated code coverage tests. |
694 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 736 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
695 // Here we use masm_-> instead of the __ macro because this is the | 737 // Here we use masm_-> instead of the __ macro because this is the |
696 // instruction that gets patched and coverage code gets in the way. | 738 // instruction that gets patched and coverage code gets in the way. |
697 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 739 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
698 // Restore value (returned from store IC), key and receiver | 740 // Restore value (returned from store IC). |
699 // registers. | |
700 if (!value_.is(rax)) __ movq(value_, rax); | 741 if (!value_.is(rax)) __ movq(value_, rax); |
701 __ pop(key_); | |
702 __ pop(receiver_); | |
703 } | 742 } |
704 | 743 |
705 | 744 |
706 void CodeGenerator::CallApplyLazy(Expression* applicand, | 745 void CodeGenerator::CallApplyLazy(Expression* applicand, |
707 Expression* receiver, | 746 Expression* receiver, |
708 VariableProxy* arguments, | 747 VariableProxy* arguments, |
709 int position) { | 748 int position) { |
710 // An optimized implementation of expressions of the form | 749 // An optimized implementation of expressions of the form |
711 // x.apply(y, arguments). | 750 // x.apply(y, arguments). |
712 // If the arguments object of the scope has not been allocated, | 751 // If the arguments object of the scope has not been allocated, |
(...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1539 frame_->SetTypeForParamAt(slot->index(), info); | 1578 frame_->SetTypeForParamAt(slot->index(), info); |
1540 } | 1579 } |
1541 if (FLAG_debug_code && info.IsSmi()) { | 1580 if (FLAG_debug_code && info.IsSmi()) { |
1542 if (slot->type() == Slot::LOCAL) { | 1581 if (slot->type() == Slot::LOCAL) { |
1543 frame_->PushLocalAt(slot->index()); | 1582 frame_->PushLocalAt(slot->index()); |
1544 } else { | 1583 } else { |
1545 frame_->PushParameterAt(slot->index()); | 1584 frame_->PushParameterAt(slot->index()); |
1546 } | 1585 } |
1547 Result var = frame_->Pop(); | 1586 Result var = frame_->Pop(); |
1548 var.ToRegister(); | 1587 var.ToRegister(); |
1549 __ AbortIfNotSmi(var.reg(), "Non-smi value in smi-typed stack slot."); | 1588 __ AbortIfNotSmi(var.reg()); |
1550 } | 1589 } |
1551 } | 1590 } |
1552 | 1591 |
1553 | 1592 |
1554 void CodeGenerator::VisitForStatement(ForStatement* node) { | 1593 void CodeGenerator::VisitForStatement(ForStatement* node) { |
1555 ASSERT(!in_spilled_code()); | 1594 ASSERT(!in_spilled_code()); |
1556 Comment cmnt(masm_, "[ ForStatement"); | 1595 Comment cmnt(masm_, "[ ForStatement"); |
1557 CodeForStatementPosition(node); | 1596 CodeForStatementPosition(node); |
1558 | 1597 |
1559 // Compile the init expression if present. | 1598 // Compile the init expression if present. |
(...skipping 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2792 // arguments. | 2831 // arguments. |
2793 | 2832 |
2794 // Prepare the stack for the call to the resolved function. | 2833 // Prepare the stack for the call to the resolved function. |
2795 Load(function); | 2834 Load(function); |
2796 | 2835 |
2797 // Allocate a frame slot for the receiver. | 2836 // Allocate a frame slot for the receiver. |
2798 frame_->Push(Factory::undefined_value()); | 2837 frame_->Push(Factory::undefined_value()); |
2799 int arg_count = args->length(); | 2838 int arg_count = args->length(); |
2800 for (int i = 0; i < arg_count; i++) { | 2839 for (int i = 0; i < arg_count; i++) { |
2801 Load(args->at(i)); | 2840 Load(args->at(i)); |
| 2841 frame_->SpillTop(); |
2802 } | 2842 } |
2803 | 2843 |
2804 // Prepare the stack for the call to ResolvePossiblyDirectEval. | 2844 // Prepare the stack for the call to ResolvePossiblyDirectEval. |
2805 frame_->PushElementAt(arg_count + 1); | 2845 frame_->PushElementAt(arg_count + 1); |
2806 if (arg_count > 0) { | 2846 if (arg_count > 0) { |
2807 frame_->PushElementAt(arg_count); | 2847 frame_->PushElementAt(arg_count); |
2808 } else { | 2848 } else { |
2809 frame_->Push(Factory::undefined_value()); | 2849 frame_->Push(Factory::undefined_value()); |
2810 } | 2850 } |
2811 | 2851 |
(...skipping 29 matching lines...) Expand all Loading... |
2841 | 2881 |
2842 // Pass the global object as the receiver and let the IC stub | 2882 // Pass the global object as the receiver and let the IC stub |
2843 // patch the stack to use the global proxy as 'this' in the | 2883 // patch the stack to use the global proxy as 'this' in the |
2844 // invoked function. | 2884 // invoked function. |
2845 LoadGlobal(); | 2885 LoadGlobal(); |
2846 | 2886 |
2847 // Load the arguments. | 2887 // Load the arguments. |
2848 int arg_count = args->length(); | 2888 int arg_count = args->length(); |
2849 for (int i = 0; i < arg_count; i++) { | 2889 for (int i = 0; i < arg_count; i++) { |
2850 Load(args->at(i)); | 2890 Load(args->at(i)); |
| 2891 frame_->SpillTop(); |
2851 } | 2892 } |
2852 | 2893 |
2853 // Push the name of the function on the frame. | 2894 // Push the name of the function on the frame. |
2854 frame_->Push(var->name()); | 2895 frame_->Push(var->name()); |
2855 | 2896 |
2856 // Call the IC initialization code. | 2897 // Call the IC initialization code. |
2857 CodeForSourcePosition(node->position()); | 2898 CodeForSourcePosition(node->position()); |
2858 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT, | 2899 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT, |
2859 arg_count, | 2900 arg_count, |
2860 loop_nesting()); | 2901 loop_nesting()); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2946 node->position()); | 2987 node->position()); |
2947 | 2988 |
2948 } else { | 2989 } else { |
2949 // Push the receiver onto the frame. | 2990 // Push the receiver onto the frame. |
2950 Load(property->obj()); | 2991 Load(property->obj()); |
2951 | 2992 |
2952 // Load the arguments. | 2993 // Load the arguments. |
2953 int arg_count = args->length(); | 2994 int arg_count = args->length(); |
2954 for (int i = 0; i < arg_count; i++) { | 2995 for (int i = 0; i < arg_count; i++) { |
2955 Load(args->at(i)); | 2996 Load(args->at(i)); |
| 2997 frame_->SpillTop(); |
2956 } | 2998 } |
2957 | 2999 |
2958 // Push the name of the function onto the frame. | 3000 // Push the name of the function onto the frame. |
2959 frame_->Push(name); | 3001 frame_->Push(name); |
2960 | 3002 |
2961 // Call the IC initialization code. | 3003 // Call the IC initialization code. |
2962 CodeForSourcePosition(node->position()); | 3004 CodeForSourcePosition(node->position()); |
2963 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET, | 3005 Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET, |
2964 arg_count, | 3006 arg_count, |
2965 loop_nesting()); | 3007 loop_nesting()); |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3392 deferred = new DeferredPostfixCountOperation(new_value.reg(), | 3434 deferred = new DeferredPostfixCountOperation(new_value.reg(), |
3393 old_value.reg(), | 3435 old_value.reg(), |
3394 is_increment, | 3436 is_increment, |
3395 new_value.type_info()); | 3437 new_value.type_info()); |
3396 } else { | 3438 } else { |
3397 deferred = new DeferredPrefixCountOperation(new_value.reg(), | 3439 deferred = new DeferredPrefixCountOperation(new_value.reg(), |
3398 is_increment, | 3440 is_increment, |
3399 new_value.type_info()); | 3441 new_value.type_info()); |
3400 } | 3442 } |
3401 | 3443 |
3402 __ JumpIfNotSmi(new_value.reg(), deferred->entry_label()); | 3444 if (new_value.is_smi()) { |
| 3445 if (FLAG_debug_code) { __ AbortIfNotSmi(new_value.reg()); } |
| 3446 } else { |
| 3447 __ JumpIfNotSmi(new_value.reg(), deferred->entry_label()); |
| 3448 } |
3403 if (is_increment) { | 3449 if (is_increment) { |
3404 __ SmiAddConstant(kScratchRegister, | 3450 __ SmiAddConstant(kScratchRegister, |
3405 new_value.reg(), | 3451 new_value.reg(), |
3406 Smi::FromInt(1), | 3452 Smi::FromInt(1), |
3407 deferred->entry_label()); | 3453 deferred->entry_label()); |
3408 } else { | 3454 } else { |
3409 __ SmiSubConstant(kScratchRegister, | 3455 __ SmiSubConstant(kScratchRegister, |
3410 new_value.reg(), | 3456 new_value.reg(), |
3411 Smi::FromInt(1), | 3457 Smi::FromInt(1), |
3412 deferred->entry_label()); | 3458 deferred->entry_label()); |
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3826 | 3872 |
3827 __ Move(kScratchRegister, Factory::null_value()); | 3873 __ Move(kScratchRegister, Factory::null_value()); |
3828 __ cmpq(obj.reg(), kScratchRegister); | 3874 __ cmpq(obj.reg(), kScratchRegister); |
3829 destination()->true_target()->Branch(equal); | 3875 destination()->true_target()->Branch(equal); |
3830 | 3876 |
3831 __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 3877 __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); |
3832 // Undetectable objects behave like undefined when tested with typeof. | 3878 // Undetectable objects behave like undefined when tested with typeof. |
3833 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 3879 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
3834 Immediate(1 << Map::kIsUndetectable)); | 3880 Immediate(1 << Map::kIsUndetectable)); |
3835 destination()->false_target()->Branch(not_zero); | 3881 destination()->false_target()->Branch(not_zero); |
3836 __ CmpInstanceType(kScratchRegister, FIRST_JS_OBJECT_TYPE); | 3882 __ movzxbq(kScratchRegister, |
3837 destination()->false_target()->Branch(less); | 3883 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); |
3838 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); | 3884 __ cmpq(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE)); |
| 3885 destination()->false_target()->Branch(below); |
| 3886 __ cmpq(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE)); |
3839 obj.Unuse(); | 3887 obj.Unuse(); |
3840 destination()->Split(less_equal); | 3888 destination()->Split(below_equal); |
3841 } | 3889 } |
3842 | 3890 |
3843 | 3891 |
3844 void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { | 3892 void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { |
3845 // This generates a fast version of: | 3893 // This generates a fast version of: |
3846 // (%_ClassOf(arg) === 'Function') | 3894 // (%_ClassOf(arg) === 'Function') |
3847 ASSERT(args->length() == 1); | 3895 ASSERT(args->length() == 1); |
3848 Load(args->at(0)); | 3896 Load(args->at(0)); |
3849 Result obj = frame_->Pop(); | 3897 Result obj = frame_->Pop(); |
3850 obj.ToRegister(); | 3898 obj.ToRegister(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3914 __ j(not_equal, &exit); | 3962 __ j(not_equal, &exit); |
3915 | 3963 |
3916 // Arguments adaptor case: Read the arguments length from the | 3964 // Arguments adaptor case: Read the arguments length from the |
3917 // adaptor frame. | 3965 // adaptor frame. |
3918 __ movq(result.reg(), | 3966 __ movq(result.reg(), |
3919 Operand(fp.reg(), ArgumentsAdaptorFrameConstants::kLengthOffset)); | 3967 Operand(fp.reg(), ArgumentsAdaptorFrameConstants::kLengthOffset)); |
3920 | 3968 |
3921 __ bind(&exit); | 3969 __ bind(&exit); |
3922 result.set_type_info(TypeInfo::Smi()); | 3970 result.set_type_info(TypeInfo::Smi()); |
3923 if (FLAG_debug_code) { | 3971 if (FLAG_debug_code) { |
3924 __ AbortIfNotSmi(result.reg(), "Computed arguments.length is not a smi."); | 3972 __ AbortIfNotSmi(result.reg()); |
3925 } | 3973 } |
3926 frame_->Push(&result); | 3974 frame_->Push(&result); |
3927 } | 3975 } |
3928 | 3976 |
3929 | 3977 |
3930 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3978 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
3931 Comment(masm_, "[ GenerateFastCharCodeAt"); | 3979 Comment(masm_, "[ GenerateFastCharCodeAt"); |
3932 ASSERT(args->length() == 2); | 3980 ASSERT(args->length() == 2); |
3933 | 3981 |
3934 Load(args->at(0)); | 3982 Load(args->at(0)); |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4322 __ CallRuntime(Runtime::kNumberUnaryMinus, 1); | 4370 __ CallRuntime(Runtime::kNumberUnaryMinus, 1); |
4323 __ movq(rbx, rax); | 4371 __ movq(rbx, rax); |
4324 | 4372 |
4325 __ bind(&heapnumber_allocated); | 4373 __ bind(&heapnumber_allocated); |
4326 | 4374 |
4327 // Return a random uint32 number in rax. | 4375 // Return a random uint32 number in rax. |
4328 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs. | 4376 // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs. |
4329 __ PrepareCallCFunction(0); | 4377 __ PrepareCallCFunction(0); |
4330 __ CallCFunction(ExternalReference::random_uint32_function(), 0); | 4378 __ CallCFunction(ExternalReference::random_uint32_function(), 0); |
4331 | 4379 |
4332 // Convert 32 random bits in eax to 0.(32 random bits) in a double | 4380 // Convert 32 random bits in rax to 0.(32 random bits) in a double |
4333 // by computing: | 4381 // by computing: |
4334 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). | 4382 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)). |
4335 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single. | 4383 __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single. |
4336 __ movd(xmm1, rcx); | 4384 __ movd(xmm1, rcx); |
4337 __ movd(xmm0, rax); | 4385 __ movd(xmm0, rax); |
4338 __ cvtss2sd(xmm1, xmm1); | 4386 __ cvtss2sd(xmm1, xmm1); |
4339 __ xorpd(xmm0, xmm1); | 4387 __ xorpd(xmm0, xmm1); |
4340 __ subsd(xmm0, xmm1); | 4388 __ subsd(xmm0, xmm1); |
4341 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0); | 4389 __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0); |
4342 | 4390 |
(...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5093 // convert it to a boolean in the condition code register or jump to | 5141 // convert it to a boolean in the condition code register or jump to |
5094 // 'false_target'/'true_target' as appropriate. | 5142 // 'false_target'/'true_target' as appropriate. |
5095 void CodeGenerator::ToBoolean(ControlDestination* dest) { | 5143 void CodeGenerator::ToBoolean(ControlDestination* dest) { |
5096 Comment cmnt(masm_, "[ ToBoolean"); | 5144 Comment cmnt(masm_, "[ ToBoolean"); |
5097 | 5145 |
5098 // The value to convert should be popped from the frame. | 5146 // The value to convert should be popped from the frame. |
5099 Result value = frame_->Pop(); | 5147 Result value = frame_->Pop(); |
5100 value.ToRegister(); | 5148 value.ToRegister(); |
5101 | 5149 |
5102 if (value.is_number()) { | 5150 if (value.is_number()) { |
5103 Comment cmnt(masm_, "ONLY_NUMBER"); | |
5104 // Fast case if TypeInfo indicates only numbers. | 5151 // Fast case if TypeInfo indicates only numbers. |
5105 if (FLAG_debug_code) { | 5152 if (FLAG_debug_code) { |
5106 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | 5153 __ AbortIfNotNumber(value.reg()); |
5107 } | 5154 } |
5108 // Smi => false iff zero. | 5155 // Smi => false iff zero. |
5109 __ SmiCompare(value.reg(), Smi::FromInt(0)); | 5156 __ SmiCompare(value.reg(), Smi::FromInt(0)); |
5110 dest->false_target()->Branch(equal); | 5157 dest->false_target()->Branch(equal); |
5111 Condition is_smi = masm_->CheckSmi(value.reg()); | 5158 Condition is_smi = masm_->CheckSmi(value.reg()); |
5112 dest->true_target()->Branch(is_smi); | 5159 dest->true_target()->Branch(is_smi); |
5113 __ fldz(); | 5160 __ fldz(); |
5114 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); | 5161 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
5115 __ FCmp(); | 5162 __ FCmp(); |
5116 value.Unuse(); | 5163 value.Unuse(); |
(...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5869 | 5916 |
5870 // Here we split control flow to the stub call and inlined cases | 5917 // Here we split control flow to the stub call and inlined cases |
5871 // before finally splitting it to the control destination. We use | 5918 // before finally splitting it to the control destination. We use |
5872 // a jump target and branching to duplicate the virtual frame at | 5919 // a jump target and branching to duplicate the virtual frame at |
5873 // the first split. We manually handle the off-frame references | 5920 // the first split. We manually handle the off-frame references |
5874 // by reconstituting them on the non-fall-through path. | 5921 // by reconstituting them on the non-fall-through path. |
5875 JumpTarget is_smi; | 5922 JumpTarget is_smi; |
5876 | 5923 |
5877 if (left_side.is_smi()) { | 5924 if (left_side.is_smi()) { |
5878 if (FLAG_debug_code) { | 5925 if (FLAG_debug_code) { |
5879 __ AbortIfNotSmi(left_side.reg(), "Non-smi value inferred as smi."); | 5926 __ AbortIfNotSmi(left_side.reg()); |
5880 } | 5927 } |
5881 } else { | 5928 } else { |
5882 Condition left_is_smi = masm_->CheckSmi(left_side.reg()); | 5929 Condition left_is_smi = masm_->CheckSmi(left_side.reg()); |
5883 is_smi.Branch(left_is_smi); | 5930 is_smi.Branch(left_is_smi); |
5884 | 5931 |
5885 bool is_loop_condition = (node->AsExpression() != NULL) && | 5932 bool is_loop_condition = (node->AsExpression() != NULL) && |
5886 node->AsExpression()->is_loop_condition(); | 5933 node->AsExpression()->is_loop_condition(); |
5887 if (!is_loop_condition && right_val->IsSmi()) { | 5934 if (!is_loop_condition && right_val->IsSmi()) { |
5888 // Right side is a constant smi and left side has been checked | 5935 // Right side is a constant smi and left side has been checked |
5889 // not to be a smi. | 5936 // not to be a smi. |
(...skipping 851 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6741 DeferredInlineSmiOperationReversed* deferred = | 6788 DeferredInlineSmiOperationReversed* deferred = |
6742 new DeferredInlineSmiOperationReversed(op, | 6789 new DeferredInlineSmiOperationReversed(op, |
6743 answer.reg(), | 6790 answer.reg(), |
6744 smi_value, | 6791 smi_value, |
6745 operand->reg(), | 6792 operand->reg(), |
6746 overwrite_mode); | 6793 overwrite_mode); |
6747 if (!operand->type_info().IsSmi()) { | 6794 if (!operand->type_info().IsSmi()) { |
6748 Condition is_smi = masm_->CheckSmi(operand->reg()); | 6795 Condition is_smi = masm_->CheckSmi(operand->reg()); |
6749 deferred->Branch(NegateCondition(is_smi)); | 6796 deferred->Branch(NegateCondition(is_smi)); |
6750 } else if (FLAG_debug_code) { | 6797 } else if (FLAG_debug_code) { |
6751 __ AbortIfNotSmi(operand->reg(), | 6798 __ AbortIfNotSmi(operand->reg()); |
6752 "Static type info claims non-smi is smi in (const SHL smi)."); | |
6753 } | 6799 } |
6754 | 6800 |
6755 __ Move(answer.reg(), smi_value); | 6801 __ Move(answer.reg(), smi_value); |
6756 __ SmiShiftLeft(answer.reg(), answer.reg(), operand->reg()); | 6802 __ SmiShiftLeft(answer.reg(), answer.reg(), operand->reg()); |
6757 operand->Unuse(); | 6803 operand->Unuse(); |
6758 | 6804 |
6759 deferred->BindExit(); | 6805 deferred->BindExit(); |
6760 } else { | 6806 } else { |
6761 // Only the least significant 5 bits of the shift value are used. | 6807 // Only the least significant 5 bits of the shift value are used. |
6762 // In the slow case, this masking is done inside the runtime call. | 6808 // In the slow case, this masking is done inside the runtime call. |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7004 answer = allocator_->Allocate(); | 7050 answer = allocator_->Allocate(); |
7005 ASSERT(answer.is_valid()); | 7051 ASSERT(answer.is_valid()); |
7006 // Check that both operands are smis using the answer register as a | 7052 // Check that both operands are smis using the answer register as a |
7007 // temporary. | 7053 // temporary. |
7008 DeferredInlineBinaryOperation* deferred = | 7054 DeferredInlineBinaryOperation* deferred = |
7009 new DeferredInlineBinaryOperation(op, | 7055 new DeferredInlineBinaryOperation(op, |
7010 answer.reg(), | 7056 answer.reg(), |
7011 left->reg(), | 7057 left->reg(), |
7012 rcx, | 7058 rcx, |
7013 overwrite_mode); | 7059 overwrite_mode); |
7014 __ JumpIfNotBothSmi(left->reg(), rcx, deferred->entry_label()); | 7060 |
| 7061 Label do_op; |
| 7062 if (right_type_info.IsSmi()) { |
| 7063 if (FLAG_debug_code) { |
| 7064 __ AbortIfNotSmi(right->reg()); |
| 7065 } |
| 7066 __ movq(answer.reg(), left->reg()); |
| 7067 // If left is not known to be a smi, check if it is. |
| 7068 // If left is not known to be a number, and it isn't a smi, check if |
| 7069 // it is a HeapNumber. |
| 7070 if (!left_type_info.IsSmi()) { |
| 7071 __ JumpIfSmi(answer.reg(), &do_op); |
| 7072 if (!left_type_info.IsNumber()) { |
| 7073 // Branch if not a heapnumber. |
| 7074 __ Cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset), |
| 7075 Factory::heap_number_map()); |
| 7076 deferred->Branch(not_equal); |
| 7077 } |
| 7078 // Load integer value into answer register using truncation. |
| 7079 __ cvttsd2si(answer.reg(), |
| 7080 FieldOperand(answer.reg(), HeapNumber::kValueOffset)); |
| 7081 // Branch if we might have overflowed. |
| 7082 // (False negative for Smi::kMinValue) |
| 7083 __ cmpq(answer.reg(), Immediate(0x80000000)); |
| 7084 deferred->Branch(equal); |
| 7085 // TODO(lrn): Inline shifts on int32 here instead of first smi-tagging. |
| 7086 __ Integer32ToSmi(answer.reg(), answer.reg()); |
| 7087 } else { |
| 7088 // Fast case - both are actually smis. |
| 7089 if (FLAG_debug_code) { |
| 7090 __ AbortIfNotSmi(left->reg()); |
| 7091 } |
| 7092 } |
| 7093 } else { |
| 7094 __ JumpIfNotBothSmi(left->reg(), rcx, deferred->entry_label()); |
| 7095 } |
| 7096 __ bind(&do_op); |
7015 | 7097 |
7016 // Perform the operation. | 7098 // Perform the operation. |
7017 switch (op) { | 7099 switch (op) { |
7018 case Token::SAR: | 7100 case Token::SAR: |
7019 __ SmiShiftArithmeticRight(answer.reg(), left->reg(), rcx); | 7101 __ SmiShiftArithmeticRight(answer.reg(), left->reg(), rcx); |
7020 break; | 7102 break; |
7021 case Token::SHR: { | 7103 case Token::SHR: { |
7022 __ SmiShiftLogicalRight(answer.reg(), | 7104 __ SmiShiftLogicalRight(answer.reg(), |
7023 left->reg(), | 7105 left->reg(), |
7024 rcx, | 7106 rcx, |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7462 key.reg(), | 7544 key.reg(), |
7463 receiver.reg()); | 7545 receiver.reg()); |
7464 | 7546 |
7465 // Check that the receiver is not a smi. | 7547 // Check that the receiver is not a smi. |
7466 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | 7548 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
7467 | 7549 |
7468 // Check that the key is a smi. | 7550 // Check that the key is a smi. |
7469 if (!key.is_smi()) { | 7551 if (!key.is_smi()) { |
7470 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); | 7552 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); |
7471 } else if (FLAG_debug_code) { | 7553 } else if (FLAG_debug_code) { |
7472 __ AbortIfNotSmi(key.reg(), "Non-smi value in smi-typed value."); | 7554 __ AbortIfNotSmi(key.reg()); |
7473 } | 7555 } |
7474 | 7556 |
7475 // Check that the receiver is a JSArray. | 7557 // Check that the receiver is a JSArray. |
7476 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); | 7558 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); |
7477 deferred->Branch(not_equal); | 7559 deferred->Branch(not_equal); |
7478 | 7560 |
7479 // Check that the key is within bounds. Both the key and the | 7561 // Check that the key is within bounds. Both the key and the |
7480 // length of the JSArray are smis. Use unsigned comparison to handle | 7562 // length of the JSArray are smis. Use unsigned comparison to handle |
7481 // negative keys. | 7563 // negative keys. |
7482 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), | 7564 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7517 masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); | 7599 masm->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); |
7518 __ movq(Operand(tmp.reg(), | 7600 __ movq(Operand(tmp.reg(), |
7519 index.reg, | 7601 index.reg, |
7520 index.scale, | 7602 index.scale, |
7521 FixedArray::kHeaderSize - kHeapObjectTag), | 7603 FixedArray::kHeaderSize - kHeapObjectTag), |
7522 value.reg()); | 7604 value.reg()); |
7523 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 7605 __ IncrementCounter(&Counters::keyed_store_inline, 1); |
7524 | 7606 |
7525 deferred->BindExit(); | 7607 deferred->BindExit(); |
7526 | 7608 |
7527 cgen_->frame()->Push(&receiver); | |
7528 cgen_->frame()->Push(&key); | |
7529 cgen_->frame()->Push(&value); | 7609 cgen_->frame()->Push(&value); |
7530 } else { | 7610 } else { |
7531 Result answer = cgen_->frame()->CallKeyedStoreIC(); | 7611 Result answer = cgen_->frame()->CallKeyedStoreIC(); |
7532 // Make sure that we do not have a test instruction after the | 7612 // Make sure that we do not have a test instruction after the |
7533 // call. A test instruction after the call is used to | 7613 // call. A test instruction after the call is used to |
7534 // indicate that we have generated an inline version of the | 7614 // indicate that we have generated an inline version of the |
7535 // keyed store. | 7615 // keyed store. |
7536 masm->nop(); | 7616 masm->nop(); |
7537 cgen_->frame()->Push(&answer); | 7617 cgen_->frame()->Push(&answer); |
7538 } | 7618 } |
7539 cgen_->UnloadReference(this); | 7619 set_unloaded(); |
7540 break; | 7620 break; |
7541 } | 7621 } |
7542 | 7622 |
7543 default: | 7623 default: |
7544 UNREACHABLE(); | 7624 UNREACHABLE(); |
7545 } | 7625 } |
7546 } | 7626 } |
7547 | 7627 |
7548 | 7628 |
7549 void FastNewClosureStub::Generate(MacroAssembler* masm) { | 7629 void FastNewClosureStub::Generate(MacroAssembler* masm) { |
(...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8891 | 8971 |
8892 // Call the function just below TOS on the stack with the given | 8972 // Call the function just below TOS on the stack with the given |
8893 // arguments. The receiver is the TOS. | 8973 // arguments. The receiver is the TOS. |
8894 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 8974 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
8895 CallFunctionFlags flags, | 8975 CallFunctionFlags flags, |
8896 int position) { | 8976 int position) { |
8897 // Push the arguments ("left-to-right") on the stack. | 8977 // Push the arguments ("left-to-right") on the stack. |
8898 int arg_count = args->length(); | 8978 int arg_count = args->length(); |
8899 for (int i = 0; i < arg_count; i++) { | 8979 for (int i = 0; i < arg_count; i++) { |
8900 Load(args->at(i)); | 8980 Load(args->at(i)); |
| 8981 frame_->SpillTop(); |
8901 } | 8982 } |
8902 | 8983 |
8903 // Record the position for debugging purposes. | 8984 // Record the position for debugging purposes. |
8904 CodeForSourcePosition(position); | 8985 CodeForSourcePosition(position); |
8905 | 8986 |
8906 // Use the shared code stub to call the function. | 8987 // Use the shared code stub to call the function. |
8907 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; | 8988 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; |
8908 CallFunctionStub call_function(arg_count, in_loop, flags); | 8989 CallFunctionStub call_function(arg_count, in_loop, flags); |
8909 Result answer = frame_->CallStub(&call_function, arg_count + 1); | 8990 Result answer = frame_->CallStub(&call_function, arg_count + 1); |
8910 // Restore context and replace function on the stack with the | 8991 // Restore context and replace function on the stack with the |
(...skipping 1096 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10007 if (!HasArgsInRegisters()) { | 10088 if (!HasArgsInRegisters()) { |
10008 __ movq(right, Operand(rsp, 1 * kPointerSize)); | 10089 __ movq(right, Operand(rsp, 1 * kPointerSize)); |
10009 __ movq(left, Operand(rsp, 2 * kPointerSize)); | 10090 __ movq(left, Operand(rsp, 2 * kPointerSize)); |
10010 } | 10091 } |
10011 | 10092 |
10012 Label not_smis; | 10093 Label not_smis; |
10013 // 2. Smi check both operands. | 10094 // 2. Smi check both operands. |
10014 if (static_operands_type_.IsSmi()) { | 10095 if (static_operands_type_.IsSmi()) { |
10015 // Skip smi check if we know that both arguments are smis. | 10096 // Skip smi check if we know that both arguments are smis. |
10016 if (FLAG_debug_code) { | 10097 if (FLAG_debug_code) { |
10017 __ AbortIfNotSmi(left, "Static type check claimed non-smi is smi."); | 10098 __ AbortIfNotSmi(left); |
10018 __ AbortIfNotSmi(right, "Static type check claimed non-smi is smi."); | 10099 __ AbortIfNotSmi(right); |
10019 } | 10100 } |
10020 if (op_ == Token::BIT_OR) { | 10101 if (op_ == Token::BIT_OR) { |
10021 // Handle OR here, since we do extra smi-checking in the or code below. | 10102 // Handle OR here, since we do extra smi-checking in the or code below. |
10022 __ SmiOr(right, right, left); | 10103 __ SmiOr(right, right, left); |
10023 GenerateReturn(masm); | 10104 GenerateReturn(masm); |
10024 return; | 10105 return; |
10025 } | 10106 } |
10026 } else { | 10107 } else { |
10027 if (op_ != Token::BIT_OR) { | 10108 if (op_ != Token::BIT_OR) { |
10028 // Skip the check for OR as it is better combined with the | 10109 // Skip the check for OR as it is better combined with the |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10191 // the four basic operations. The stub stays in the DEFAULT state | 10272 // the four basic operations. The stub stays in the DEFAULT state |
10192 // forever for all other operations (also if smi code is skipped). | 10273 // forever for all other operations (also if smi code is skipped). |
10193 GenerateTypeTransition(masm); | 10274 GenerateTypeTransition(masm); |
10194 } | 10275 } |
10195 | 10276 |
10196 Label not_floats; | 10277 Label not_floats; |
10197 // rax: y | 10278 // rax: y |
10198 // rdx: x | 10279 // rdx: x |
10199 if (static_operands_type_.IsNumber() && FLAG_debug_code) { | 10280 if (static_operands_type_.IsNumber() && FLAG_debug_code) { |
10200 // Assert at runtime that inputs are only numbers. | 10281 // Assert at runtime that inputs are only numbers. |
10201 __ AbortIfNotNumber(rdx, "GenericBinaryOpStub operand not a number."); | 10282 __ AbortIfNotNumber(rdx); |
10202 __ AbortIfNotNumber(rax, "GenericBinaryOpStub operand not a number."); | 10283 __ AbortIfNotNumber(rax); |
10203 } else { | 10284 } else { |
10204 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); | 10285 FloatingPointHelper::CheckNumberOperands(masm, &call_runtime); |
10205 } | 10286 } |
10206 // Fast-case: Both operands are numbers. | 10287 // Fast-case: Both operands are numbers. |
10207 // xmm4 and xmm5 are volatile XMM registers. | 10288 // xmm4 and xmm5 are volatile XMM registers. |
10208 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); | 10289 FloatingPointHelper::LoadFloatOperands(masm, xmm4, xmm5); |
10209 | 10290 |
10210 switch (op_) { | 10291 switch (op_) { |
10211 case Token::ADD: __ addsd(xmm4, xmm5); break; | 10292 case Token::ADD: __ addsd(xmm4, xmm5); break; |
10212 case Token::SUB: __ subsd(xmm4, xmm5); break; | 10293 case Token::SUB: __ subsd(xmm4, xmm5); break; |
(...skipping 1369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11582 // Call the function from C++. | 11663 // Call the function from C++. |
11583 return FUNCTION_CAST<ModuloFunction>(buffer); | 11664 return FUNCTION_CAST<ModuloFunction>(buffer); |
11584 } | 11665 } |
11585 | 11666 |
11586 #endif | 11667 #endif |
11587 | 11668 |
11588 | 11669 |
11589 #undef __ | 11670 #undef __ |
11590 | 11671 |
11591 } } // namespace v8::internal | 11672 } } // namespace v8::internal |
| 11673 |
| 11674 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |