Chromium Code Reviews| 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 |