OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 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 19 matching lines...) Expand all Loading... | |
30 | 30 |
31 #include "v8.h" | 31 #include "v8.h" |
32 | 32 |
33 #include "bootstrapper.h" | 33 #include "bootstrapper.h" |
34 #include "codegen-inl.h" | 34 #include "codegen-inl.h" |
35 #include "debug.h" | 35 #include "debug.h" |
36 #include "ic-inl.h" | 36 #include "ic-inl.h" |
37 #include "parser.h" | 37 #include "parser.h" |
38 #include "register-allocator-inl.h" | 38 #include "register-allocator-inl.h" |
39 #include "scopes.h" | 39 #include "scopes.h" |
40 #include "macro-assembler.h" | |
William Hesse
2009/06/24 11:39:35
Surely this was already included through a depende
| |
40 | 41 |
41 // TODO(X64): Remove compiler.h when compiler test is removed. | 42 // TODO(X64): Remove compiler.h when compiler test is removed. |
42 #include "compiler.h" | 43 #include "compiler.h" |
43 | 44 |
44 namespace v8 { | 45 namespace v8 { |
45 namespace internal { | 46 namespace internal { |
46 | 47 |
47 #define __ ACCESS_MASM(masm_) | 48 #define __ ACCESS_MASM(masm_) |
48 | 49 |
49 // ------------------------------------------------------------------------- | 50 // ------------------------------------------------------------------------- |
(...skipping 1279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1329 // Use global object as receiver. | 1330 // Use global object as receiver. |
1330 LoadGlobalReceiver(); | 1331 LoadGlobalReceiver(); |
1331 } else { | 1332 } else { |
1332 // The reference's size is non-negative. | 1333 // The reference's size is non-negative. |
1333 frame_->PushElementAt(ref.size()); | 1334 frame_->PushElementAt(ref.size()); |
1334 } | 1335 } |
1335 | 1336 |
1336 // Call the function. | 1337 // Call the function. |
1337 CallWithArguments(args, node->position()); | 1338 CallWithArguments(args, node->position()); |
1338 } | 1339 } |
1339 | |
1340 } else { | 1340 } else { |
1341 // ---------------------------------- | 1341 // ---------------------------------- |
1342 // JavaScript example: 'foo(1, 2, 3)' // foo is not global | 1342 // JavaScript example: 'foo(1, 2, 3)' // foo is not global |
1343 // ---------------------------------- | 1343 // ---------------------------------- |
1344 | 1344 |
1345 // Load the function. | 1345 // Load the function. |
1346 Load(function); | 1346 Load(function); |
1347 | 1347 |
1348 // Pass the global proxy as the receiver. | 1348 // Pass the global proxy as the receiver. |
1349 LoadGlobalReceiver(); | 1349 LoadGlobalReceiver(); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1397 } | 1397 } |
1398 | 1398 |
1399 ZoneList<Expression*>* args = node->arguments(); | 1399 ZoneList<Expression*>* args = node->arguments(); |
1400 Comment cmnt(masm_, "[ CallRuntime"); | 1400 Comment cmnt(masm_, "[ CallRuntime"); |
1401 Runtime::Function* function = node->function(); | 1401 Runtime::Function* function = node->function(); |
1402 | 1402 |
1403 if (function == NULL) { | 1403 if (function == NULL) { |
1404 // Prepare stack for calling JS runtime function. | 1404 // Prepare stack for calling JS runtime function. |
1405 frame_->Push(node->name()); | 1405 frame_->Push(node->name()); |
1406 // Push the builtins object found in the current global object. | 1406 // Push the builtins object found in the current global object. |
1407 Result temp = allocator()->Allocate(); | 1407 __ movq(kScratchRegister, GlobalObject()); |
1408 ASSERT(temp.is_valid()); | 1408 __ movq(kScratchRegister, |
1409 __ movq(temp.reg(), GlobalObject()); | 1409 FieldOperand(kScratchRegister, GlobalObject::kBuiltinsOffset)); |
1410 __ movq(temp.reg(), | 1410 frame_->Push(kScratchRegister); |
William Hesse
2009/06/24 11:39:35
This must be reversed again - we cannot push kScra
| |
1411 FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); | |
1412 frame_->Push(&temp); | |
1413 } | 1411 } |
1414 | 1412 |
1415 // Push the arguments ("left-to-right"). | 1413 // Push the arguments ("left-to-right"). |
1416 int arg_count = args->length(); | 1414 int arg_count = args->length(); |
1417 for (int i = 0; i < arg_count; i++) { | 1415 for (int i = 0; i < arg_count; i++) { |
1418 Load(args->at(i)); | 1416 Load(args->at(i)); |
1419 } | 1417 } |
1420 | 1418 |
1421 if (function == NULL) { | 1419 if (function == NULL) { |
1422 // Call the JS runtime function. | 1420 // Call the JS runtime function. |
(...skipping 867 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2290 int MinorKey() { | 2288 int MinorKey() { |
2291 // Encode the parameters in a unique 16 bit value. | 2289 // Encode the parameters in a unique 16 bit value. |
2292 return OpBits::encode(op_) | 2290 return OpBits::encode(op_) |
2293 | ModeBits::encode(mode_) | 2291 | ModeBits::encode(mode_) |
2294 | FlagBits::encode(flags_); | 2292 | FlagBits::encode(flags_); |
2295 } | 2293 } |
2296 void Generate(MacroAssembler* masm); | 2294 void Generate(MacroAssembler* masm); |
2297 }; | 2295 }; |
2298 | 2296 |
2299 | 2297 |
2298 class DeferredInlineBinaryOperation: public DeferredCode { | |
2299 public: | |
2300 DeferredInlineBinaryOperation(Token::Value op, | |
2301 Register dst, | |
2302 Register left, | |
2303 Register right, | |
2304 OverwriteMode mode) | |
2305 : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { | |
2306 set_comment("[ DeferredInlineBinaryOperation"); | |
2307 } | |
2308 | |
2309 virtual void Generate(); | |
2310 | |
2311 private: | |
2312 Token::Value op_; | |
2313 Register dst_; | |
2314 Register left_; | |
2315 Register right_; | |
2316 OverwriteMode mode_; | |
2317 }; | |
2318 | |
2319 | |
2320 void DeferredInlineBinaryOperation::Generate() { | |
2321 __ push(left_); | |
2322 __ push(right_); | |
2323 GenericBinaryOpStub stub(op_, mode_, SMI_CODE_INLINED); | |
2324 __ CallStub(&stub); | |
2325 if (!dst_.is(rax)) __ movq(dst_, rax); | |
2326 } | |
2327 | |
2328 | |
2300 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 2329 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
2301 SmiAnalysis* type, | 2330 SmiAnalysis* type, |
2302 OverwriteMode overwrite_mode) { | 2331 OverwriteMode overwrite_mode) { |
2303 Comment cmnt(masm_, "[ BinaryOperation"); | 2332 Comment cmnt(masm_, "[ BinaryOperation"); |
2304 Comment cmnt_token(masm_, Token::String(op)); | 2333 Comment cmnt_token(masm_, Token::String(op)); |
2305 | 2334 |
2306 if (op == Token::COMMA) { | 2335 if (op == Token::COMMA) { |
2307 // Simply discard left value. | 2336 // Simply discard left value. |
2308 frame_->Nip(1); | 2337 frame_->Nip(1); |
2309 return; | 2338 return; |
(...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2616 } else { | 2645 } else { |
2617 LikelySmiBinaryOperation(op, operand, &constant_operand, | 2646 LikelySmiBinaryOperation(op, operand, &constant_operand, |
2618 overwrite_mode); | 2647 overwrite_mode); |
2619 } | 2648 } |
2620 break; | 2649 break; |
2621 } | 2650 } |
2622 } | 2651 } |
2623 ASSERT(!operand->is_valid()); | 2652 ASSERT(!operand->is_valid()); |
2624 } | 2653 } |
2625 | 2654 |
2655 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | |
2656 Result* left, | |
2657 Result* right, | |
2658 OverwriteMode overwrite_mode) { | |
2659 // Special handling of div and mod because they use fixed registers. | |
2660 if (op == Token::DIV || op == Token::MOD) { | |
2661 // We need rax as the quotient register, rdx as the remainder | |
2662 // register, neither left nor right in rax or rdx, and left copied | |
2663 // to rax. | |
2664 Result quotient; | |
2665 Result remainder; | |
2666 bool left_is_in_rax = false; | |
2667 // Step 1: get rax for quotient. | |
2668 if ((left->is_register() && left->reg().is(rax)) || | |
2669 (right->is_register() && right->reg().is(rax))) { | |
2670 // One or both is in rax. Use a fresh non-rdx register for | |
2671 // them. | |
2672 Result fresh = allocator_->Allocate(); | |
2673 ASSERT(fresh.is_valid()); | |
2674 if (fresh.reg().is(rdx)) { | |
2675 remainder = fresh; | |
2676 fresh = allocator_->Allocate(); | |
2677 ASSERT(fresh.is_valid()); | |
2678 } | |
2679 if (left->is_register() && left->reg().is(rax)) { | |
2680 quotient = *left; | |
2681 *left = fresh; | |
2682 left_is_in_rax = true; | |
2683 } | |
2684 if (right->is_register() && right->reg().is(rax)) { | |
2685 quotient = *right; | |
2686 *right = fresh; | |
2687 } | |
2688 __ movq(fresh.reg(), rax); | |
2689 } else { | |
2690 // Neither left nor right is in rax. | |
2691 quotient = allocator_->Allocate(rax); | |
2692 } | |
2693 ASSERT(quotient.is_register() && quotient.reg().is(rax)); | |
2694 ASSERT(!(left->is_register() && left->reg().is(rax))); | |
2695 ASSERT(!(right->is_register() && right->reg().is(rax))); | |
2696 | |
2697 // Step 2: get rdx for remainder if necessary. | |
2698 if (!remainder.is_valid()) { | |
2699 if ((left->is_register() && left->reg().is(rdx)) || | |
2700 (right->is_register() && right->reg().is(rdx))) { | |
2701 Result fresh = allocator_->Allocate(); | |
2702 ASSERT(fresh.is_valid()); | |
2703 if (left->is_register() && left->reg().is(rdx)) { | |
2704 remainder = *left; | |
2705 *left = fresh; | |
2706 } | |
2707 if (right->is_register() && right->reg().is(rdx)) { | |
2708 remainder = *right; | |
2709 *right = fresh; | |
2710 } | |
2711 __ movq(fresh.reg(), rdx); | |
2712 } else { | |
2713 // Neither left nor right is in rdx. | |
2714 remainder = allocator_->Allocate(rdx); | |
2715 } | |
2716 } | |
2717 ASSERT(remainder.is_register() && remainder.reg().is(rdx)); | |
2718 ASSERT(!(left->is_register() && left->reg().is(rdx))); | |
2719 ASSERT(!(right->is_register() && right->reg().is(rdx))); | |
2720 | |
2721 left->ToRegister(); | |
2722 right->ToRegister(); | |
2723 frame_->Spill(rax); | |
2724 frame_->Spill(rdx); | |
2725 | |
2726 // Check that left and right are smi tagged. | |
2727 DeferredInlineBinaryOperation* deferred = | |
2728 new DeferredInlineBinaryOperation(op, | |
2729 (op == Token::DIV) ? rax : rdx, | |
2730 left->reg(), | |
2731 right->reg(), | |
2732 overwrite_mode); | |
2733 if (left->reg().is(right->reg())) { | |
2734 __ testl(left->reg(), Immediate(kSmiTagMask)); | |
2735 } else { | |
2736 // Use the quotient register as a scratch for the tag check. | |
2737 if (!left_is_in_rax) __ movq(rax, left->reg()); | |
2738 left_is_in_rax = false; // About to destroy the value in rax. | |
2739 __ or_(rax, right->reg()); | |
2740 ASSERT(kSmiTag == 0); // Adjust test if not the case. | |
2741 __ testl(rax, Immediate(kSmiTagMask)); | |
2742 } | |
2743 deferred->Branch(not_zero); | |
2744 | |
2745 if (!left_is_in_rax) __ movq(rax, left->reg()); | |
2746 // Sign extend rax into rdx:rax. | |
2747 __ cqo(); | |
2748 // Check for 0 divisor. | |
2749 __ testq(right->reg(), right->reg()); | |
2750 deferred->Branch(zero); | |
2751 // Divide rdx:rax by the right operand. | |
2752 __ idiv(right->reg()); | |
2753 | |
2754 // Complete the operation. | |
2755 if (op == Token::DIV) { | |
2756 // Check for negative zero result. If result is zero, and divisor | |
2757 // is negative, return a floating point negative zero. The | |
2758 // virtual frame is unchanged in this block, so local control flow | |
2759 // can use a Label rather than a JumpTarget. | |
2760 Label non_zero_result; | |
2761 __ testq(left->reg(), left->reg()); | |
2762 __ j(not_zero, &non_zero_result); | |
2763 __ testq(right->reg(), right->reg()); | |
2764 deferred->Branch(negative); | |
2765 __ bind(&non_zero_result); | |
2766 // Check for the corner case of dividing the most negative smi by | |
2767 // -1. We cannot use the overflow flag, since it is not set by | |
2768 // idiv instruction. | |
2769 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | |
2770 __ cmpq(rax, Immediate(0x40000000)); | |
2771 deferred->Branch(equal); | |
2772 // Check that the remainder is zero. | |
2773 __ testq(rdx, rdx); | |
2774 deferred->Branch(not_zero); | |
2775 // Tag the result and store it in the quotient register. | |
2776 ASSERT(kSmiTagSize == times_2); // adjust code if not the case | |
2777 __ lea(rax, Operand(rax, rax, times_1, kSmiTag)); | |
2778 deferred->BindExit(); | |
2779 left->Unuse(); | |
2780 right->Unuse(); | |
2781 frame_->Push("ient); | |
2782 } else { | |
2783 ASSERT(op == Token::MOD); | |
2784 // Check for a negative zero result. If the result is zero, and | |
2785 // the dividend is negative, return a floating point negative | |
2786 // zero. The frame is unchanged in this block, so local control | |
2787 // flow can use a Label rather than a JumpTarget. | |
2788 Label non_zero_result; | |
2789 __ testq(rdx, rdx); | |
2790 __ j(not_zero, &non_zero_result); | |
2791 __ testq(left->reg(), left->reg()); | |
2792 deferred->Branch(negative); | |
2793 __ bind(&non_zero_result); | |
2794 deferred->BindExit(); | |
2795 left->Unuse(); | |
2796 right->Unuse(); | |
2797 frame_->Push(&remainder); | |
2798 } | |
2799 return; | |
2800 } | |
2801 | |
2802 // Special handling of shift operations because they use fixed | |
2803 // registers. | |
2804 if (op == Token::SHL || op == Token::SHR || op == Token::SAR) { | |
2805 // Move left out of rcx if necessary. | |
2806 if (left->is_register() && left->reg().is(rcx)) { | |
2807 *left = allocator_->Allocate(); | |
2808 ASSERT(left->is_valid()); | |
2809 __ movq(left->reg(), rcx); | |
2810 } | |
2811 right->ToRegister(rcx); | |
2812 left->ToRegister(); | |
2813 ASSERT(left->is_register() && !left->reg().is(rcx)); | |
2814 ASSERT(right->is_register() && right->reg().is(rcx)); | |
2815 | |
2816 // We will modify right, it must be spilled. | |
2817 frame_->Spill(rcx); | |
2818 | |
2819 // Use a fresh answer register to avoid spilling the left operand. | |
2820 Result answer = allocator_->Allocate(); | |
2821 ASSERT(answer.is_valid()); | |
2822 // Check that both operands are smis using the answer register as a | |
2823 // temporary. | |
2824 DeferredInlineBinaryOperation* deferred = | |
2825 new DeferredInlineBinaryOperation(op, | |
2826 answer.reg(), | |
2827 left->reg(), | |
2828 rcx, | |
2829 overwrite_mode); | |
2830 __ movq(answer.reg(), left->reg()); | |
2831 __ or_(answer.reg(), rcx); | |
2832 __ testl(answer.reg(), Immediate(kSmiTagMask)); | |
2833 deferred->Branch(not_zero); | |
2834 | |
2835 // Untag both operands. | |
2836 __ movq(answer.reg(), left->reg()); | |
2837 __ sar(answer.reg(), Immediate(kSmiTagSize)); | |
2838 __ sar(rcx, Immediate(kSmiTagSize)); | |
2839 // Perform the operation. | |
2840 switch (op) { | |
2841 case Token::SAR: | |
2842 __ sar(answer.reg()); | |
2843 // No checks of result necessary | |
2844 break; | |
2845 case Token::SHR: { | |
2846 Label result_ok; | |
2847 __ shr(answer.reg()); | |
2848 // Check that the *unsigned* result fits in a smi. Neither of | |
2849 // the two high-order bits can be set: | |
2850 // * 0x80000000: high bit would be lost when smi tagging. | |
2851 // * 0x40000000: this number would convert to negative when smi | |
2852 // tagging. | |
2853 // These two cases can only happen with shifts by 0 or 1 when | |
2854 // handed a valid smi. If the answer cannot be represented by a | |
2855 // smi, restore the left and right arguments, and jump to slow | |
2856 // case. The low bit of the left argument may be lost, but only | |
2857 // in a case where it is dropped anyway. | |
2858 __ testl(answer.reg(), Immediate(0xc0000000)); | |
2859 __ j(zero, &result_ok); | |
2860 ASSERT(kSmiTag == 0); | |
2861 __ shl(rcx, Immediate(kSmiTagSize)); | |
2862 deferred->Jump(); | |
2863 __ bind(&result_ok); | |
2864 break; | |
2865 } | |
2866 case Token::SHL: { | |
2867 Label result_ok; | |
2868 __ shl(answer.reg()); | |
2869 // Check that the *signed* result fits in a smi. | |
2870 __ cmpq(answer.reg(), Immediate(0xc0000000)); | |
2871 __ j(positive, &result_ok); | |
2872 ASSERT(kSmiTag == 0); | |
2873 __ shl(rcx, Immediate(kSmiTagSize)); | |
2874 deferred->Jump(); | |
2875 __ bind(&result_ok); | |
2876 break; | |
2877 } | |
2878 default: | |
2879 UNREACHABLE(); | |
2880 } | |
2881 // Smi-tag the result in answer. | |
2882 ASSERT(kSmiTagSize == 1); // Adjust code if not the case. | |
2883 __ lea(answer.reg(), | |
2884 Operand(answer.reg(), answer.reg(), times_1, kSmiTag)); | |
2885 deferred->BindExit(); | |
2886 left->Unuse(); | |
2887 right->Unuse(); | |
2888 frame_->Push(&answer); | |
2889 return; | |
2890 } | |
2891 | |
2892 // Handle the other binary operations. | |
2893 left->ToRegister(); | |
2894 right->ToRegister(); | |
2895 // A newly allocated register answer is used to hold the answer. The | |
2896 // registers containing left and right are not modified so they don't | |
2897 // need to be spilled in the fast case. | |
2898 Result answer = allocator_->Allocate(); | |
2899 ASSERT(answer.is_valid()); | |
2900 | |
2901 // Perform the smi tag check. | |
2902 DeferredInlineBinaryOperation* deferred = | |
2903 new DeferredInlineBinaryOperation(op, | |
2904 answer.reg(), | |
2905 left->reg(), | |
2906 right->reg(), | |
2907 overwrite_mode); | |
2908 if (left->reg().is(right->reg())) { | |
2909 __ testl(left->reg(), Immediate(kSmiTagMask)); | |
2910 } else { | |
2911 __ movq(answer.reg(), left->reg()); | |
2912 __ or_(answer.reg(), right->reg()); | |
2913 ASSERT(kSmiTag == 0); // Adjust test if not the case. | |
2914 __ testl(answer.reg(), Immediate(kSmiTagMask)); | |
2915 } | |
2916 deferred->Branch(not_zero); | |
2917 __ movq(answer.reg(), left->reg()); | |
2918 switch (op) { | |
2919 case Token::ADD: | |
2920 __ addq(answer.reg(), right->reg()); // Add optimistically. | |
William Hesse
2009/06/24 11:39:35
I think we want addl here.
| |
2921 deferred->Branch(overflow); | |
2922 break; | |
2923 | |
2924 case Token::SUB: | |
2925 __ subq(answer.reg(), right->reg()); // Subtract optimistically. | |
William Hesse
2009/06/24 11:39:35
subl
| |
2926 deferred->Branch(overflow); | |
2927 break; | |
2928 | |
2929 case Token::MUL: { | |
2930 // If the smi tag is 0 we can just leave the tag on one operand. | |
2931 ASSERT(kSmiTag == 0); // Adjust code below if not the case. | |
2932 // Remove smi tag from the left operand (but keep sign). | |
2933 // Left-hand operand has been copied into answer. | |
2934 __ sar(answer.reg(), Immediate(kSmiTagSize)); | |
2935 // Do multiplication of smis, leaving result in answer. | |
2936 __ imull(answer.reg(), right->reg()); | |
2937 // Go slow on overflows. | |
2938 deferred->Branch(overflow); | |
2939 // Check for negative zero result. If product is zero, and one | |
2940 // argument is negative, go to slow case. The frame is unchanged | |
2941 // in this block, so local control flow can use a Label rather | |
2942 // than a JumpTarget. | |
2943 Label non_zero_result; | |
2944 __ testq(answer.reg(), answer.reg()); | |
2945 __ j(not_zero, &non_zero_result); | |
2946 __ movq(answer.reg(), left->reg()); | |
2947 __ or_(answer.reg(), right->reg()); | |
2948 deferred->Branch(negative); | |
2949 __ xor_(answer.reg(), answer.reg()); // Positive 0 is correct. | |
2950 __ bind(&non_zero_result); | |
2951 break; | |
2952 } | |
2953 | |
2954 case Token::BIT_OR: | |
2955 __ or_(answer.reg(), right->reg()); | |
2956 break; | |
2957 | |
2958 case Token::BIT_AND: | |
2959 __ and_(answer.reg(), right->reg()); | |
2960 break; | |
2961 | |
2962 case Token::BIT_XOR: | |
2963 __ xor_(answer.reg(), right->reg()); | |
2964 break; | |
2965 | |
2966 default: | |
2967 UNREACHABLE(); | |
2968 break; | |
2969 } | |
2970 deferred->BindExit(); | |
2971 left->Unuse(); | |
2972 right->Unuse(); | |
2973 frame_->Push(&answer); | |
2974 } | |
2975 | |
2976 | |
2626 #undef __ | 2977 #undef __ |
2627 #define __ ACCESS_MASM(masm) | 2978 #define __ ACCESS_MASM(masm) |
2628 | 2979 |
2629 | 2980 |
2630 Handle<String> Reference::GetName() { | 2981 Handle<String> Reference::GetName() { |
2631 ASSERT(type_ == NAMED); | 2982 ASSERT(type_ == NAMED); |
2632 Property* property = expression_->AsProperty(); | 2983 Property* property = expression_->AsProperty(); |
2633 if (property == NULL) { | 2984 if (property == NULL) { |
2634 // Global variable reference treated as a named property reference. | 2985 // Global variable reference treated as a named property reference. |
2635 VariableProxy* proxy = expression_->AsVariableProxy(); | 2986 VariableProxy* proxy = expression_->AsVariableProxy(); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2676 if (is_global || | 3027 if (is_global || |
2677 cgen_->scope()->is_global_scope() || | 3028 cgen_->scope()->is_global_scope() || |
2678 cgen_->loop_nesting() == 0) { | 3029 cgen_->loop_nesting() == 0) { |
2679 Comment cmnt(masm, "[ Load from named Property"); | 3030 Comment cmnt(masm, "[ Load from named Property"); |
2680 cgen_->frame()->Push(GetName()); | 3031 cgen_->frame()->Push(GetName()); |
2681 | 3032 |
2682 RelocInfo::Mode mode = is_global | 3033 RelocInfo::Mode mode = is_global |
2683 ? RelocInfo::CODE_TARGET_CONTEXT | 3034 ? RelocInfo::CODE_TARGET_CONTEXT |
2684 : RelocInfo::CODE_TARGET; | 3035 : RelocInfo::CODE_TARGET; |
2685 Result answer = cgen_->frame()->CallLoadIC(mode); | 3036 Result answer = cgen_->frame()->CallLoadIC(mode); |
2686 // A test eax instruction following the call signals that the | 3037 // A test rax instruction following the call signals that the |
2687 // inobject property case was inlined. Ensure that there is not | 3038 // inobject property case was inlined. Ensure that there is not |
2688 // a test eax instruction here. | 3039 // a test rax instruction here. |
2689 __ nop(); | 3040 __ nop(); |
2690 cgen_->frame()->Push(&answer); | 3041 cgen_->frame()->Push(&answer); |
2691 } else { | 3042 } else { |
2692 // Inline the inobject property case. | 3043 // Inline the inobject property case. |
2693 Comment cmnt(masm, "[ Inlined named property load"); | 3044 Comment cmnt(masm, "[ Inlined named property load"); |
2694 Result receiver = cgen_->frame()->Pop(); | 3045 Result receiver = cgen_->frame()->Pop(); |
2695 receiver.ToRegister(); | 3046 receiver.ToRegister(); |
2696 | 3047 |
2697 Result value = cgen_->allocator()->Allocate(); | 3048 Result value = cgen_->allocator()->Allocate(); |
2698 ASSERT(value.is_valid()); | 3049 ASSERT(value.is_valid()); |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2863 __ bind(&true_result); | 3214 __ bind(&true_result); |
2864 __ movq(rax, Immediate(1)); | 3215 __ movq(rax, Immediate(1)); |
2865 __ ret(1 * kPointerSize); | 3216 __ ret(1 * kPointerSize); |
2866 __ bind(&false_result); | 3217 __ bind(&false_result); |
2867 __ xor_(rax, rax); | 3218 __ xor_(rax, rax); |
2868 __ ret(1 * kPointerSize); | 3219 __ ret(1 * kPointerSize); |
2869 } | 3220 } |
2870 | 3221 |
2871 | 3222 |
2872 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 3223 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
2873 return false; // UNIMPLEMENTED. | 3224 // TODO(X64): This method is identical to the ia32 version. |
3225 // Either find a reason to change it, or move it somewhere where it can be | |
3226 // shared. (Notice: It assumes that a Smi can fit in an int). | |
3227 | |
3228 Object* answer_object = Heap::undefined_value(); | |
3229 switch (op) { | |
3230 case Token::ADD: | |
3231 if (Smi::IsValid(left + right)) { | |
3232 answer_object = Smi::FromInt(left + right); | |
3233 } | |
3234 break; | |
3235 case Token::SUB: | |
3236 if (Smi::IsValid(left - right)) { | |
3237 answer_object = Smi::FromInt(left - right); | |
3238 } | |
3239 break; | |
3240 case Token::MUL: { | |
3241 double answer = static_cast<double>(left) * right; | |
3242 if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) { | |
3243 // If the product is zero and the non-zero factor is negative, | |
3244 // the spec requires us to return floating point negative zero. | |
3245 if (answer != 0 || (left >= 0 && right >= 0)) { | |
3246 answer_object = Smi::FromInt(static_cast<int>(answer)); | |
3247 } | |
3248 } | |
3249 } | |
3250 break; | |
3251 case Token::DIV: | |
3252 case Token::MOD: | |
3253 break; | |
3254 case Token::BIT_OR: | |
3255 answer_object = Smi::FromInt(left | right); | |
3256 break; | |
3257 case Token::BIT_AND: | |
3258 answer_object = Smi::FromInt(left & right); | |
3259 break; | |
3260 case Token::BIT_XOR: | |
3261 answer_object = Smi::FromInt(left ^ right); | |
3262 break; | |
3263 | |
3264 case Token::SHL: { | |
3265 int shift_amount = right & 0x1F; | |
3266 if (Smi::IsValid(left << shift_amount)) { | |
3267 answer_object = Smi::FromInt(left << shift_amount); | |
3268 } | |
3269 break; | |
3270 } | |
3271 case Token::SHR: { | |
3272 int shift_amount = right & 0x1F; | |
3273 unsigned int unsigned_left = left; | |
3274 unsigned_left >>= shift_amount; | |
3275 if (unsigned_left <= static_cast<unsigned int>(Smi::kMaxValue)) { | |
3276 answer_object = Smi::FromInt(unsigned_left); | |
3277 } | |
3278 break; | |
3279 } | |
3280 case Token::SAR: { | |
3281 int shift_amount = right & 0x1F; | |
3282 unsigned int unsigned_left = left; | |
3283 if (left < 0) { | |
3284 // Perform arithmetic shift of a negative number by | |
3285 // complementing number, logical shifting, complementing again. | |
3286 unsigned_left = ~unsigned_left; | |
3287 unsigned_left >>= shift_amount; | |
3288 unsigned_left = ~unsigned_left; | |
3289 } else { | |
3290 unsigned_left >>= shift_amount; | |
3291 } | |
3292 ASSERT(Smi::IsValid(unsigned_left)); // Converted to signed. | |
3293 answer_object = Smi::FromInt(unsigned_left); // Converted to signed. | |
3294 break; | |
3295 } | |
3296 default: | |
3297 UNREACHABLE(); | |
3298 break; | |
3299 } | |
3300 if (answer_object == Heap::undefined_value()) { | |
3301 return false; | |
3302 } | |
3303 frame_->Push(Handle<Object>(answer_object)); | |
3304 return true; | |
2874 } | 3305 } |
2875 | 3306 |
2876 | 3307 |
2877 void CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | |
2878 Result* left, | |
2879 Result* right, | |
2880 OverwriteMode overwrite_mode) { | |
2881 UNIMPLEMENTED(); | |
2882 } | |
2883 | 3308 |
2884 | 3309 |
2885 // End of CodeGenerator implementation. | 3310 // End of CodeGenerator implementation. |
2886 | 3311 |
2887 void UnarySubStub::Generate(MacroAssembler* masm) { | 3312 void UnarySubStub::Generate(MacroAssembler* masm) { |
2888 UNIMPLEMENTED(); | 3313 UNIMPLEMENTED(); |
2889 } | 3314 } |
2890 | 3315 |
2891 class CompareStub: public CodeStub { | 3316 class CompareStub: public CodeStub { |
2892 public: | 3317 public: |
(...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3562 __ testl(rdx, Immediate(kSmiTagMask)); | 3987 __ testl(rdx, Immediate(kSmiTagMask)); |
3563 __ j(zero, &test_other); // argument in rdx is OK | 3988 __ j(zero, &test_other); // argument in rdx is OK |
3564 __ movq(kScratchRegister, | 3989 __ movq(kScratchRegister, |
3565 Factory::heap_number_map(), | 3990 Factory::heap_number_map(), |
3566 RelocInfo::EMBEDDED_OBJECT); | 3991 RelocInfo::EMBEDDED_OBJECT); |
3567 __ cmpq(kScratchRegister, FieldOperand(rdx, HeapObject::kMapOffset)); | 3992 __ cmpq(kScratchRegister, FieldOperand(rdx, HeapObject::kMapOffset)); |
3568 __ j(not_equal, non_float); // argument in rdx is not a number -> NaN | 3993 __ j(not_equal, non_float); // argument in rdx is not a number -> NaN |
3569 | 3994 |
3570 __ bind(&test_other); | 3995 __ bind(&test_other); |
3571 __ testl(rax, Immediate(kSmiTagMask)); | 3996 __ testl(rax, Immediate(kSmiTagMask)); |
3572 __ j(zero, &done); // argument in eax is OK | 3997 __ j(zero, &done); // argument in rax is OK |
3573 __ movq(kScratchRegister, | 3998 __ movq(kScratchRegister, |
3574 Factory::heap_number_map(), | 3999 Factory::heap_number_map(), |
3575 RelocInfo::EMBEDDED_OBJECT); | 4000 RelocInfo::EMBEDDED_OBJECT); |
3576 __ cmpq(kScratchRegister, FieldOperand(rax, HeapObject::kMapOffset)); | 4001 __ cmpq(kScratchRegister, FieldOperand(rax, HeapObject::kMapOffset)); |
3577 __ j(not_equal, non_float); // argument in rax is not a number -> NaN | 4002 __ j(not_equal, non_float); // argument in rax is not a number -> NaN |
3578 | 4003 |
3579 // Fall-through: Both operands are numbers. | 4004 // Fall-through: Both operands are numbers. |
3580 __ bind(&done); | 4005 __ bind(&done); |
3581 } | 4006 } |
3582 | 4007 |
(...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3990 break; | 4415 break; |
3991 default: | 4416 default: |
3992 UNREACHABLE(); | 4417 UNREACHABLE(); |
3993 } | 4418 } |
3994 } | 4419 } |
3995 | 4420 |
3996 | 4421 |
3997 #undef __ | 4422 #undef __ |
3998 | 4423 |
3999 } } // namespace v8::internal | 4424 } } // namespace v8::internal |
OLD | NEW |