OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 3099 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3110 case Token::NOT: | 3110 case Token::NOT: |
3111 case Token::DELETE: | 3111 case Token::DELETE: |
3112 case Token::TYPEOF: | 3112 case Token::TYPEOF: |
3113 UNREACHABLE(); // handled above | 3113 UNREACHABLE(); // handled above |
3114 break; | 3114 break; |
3115 | 3115 |
3116 case Token::SUB: { | 3116 case Token::SUB: { |
3117 GenericUnaryOpStub stub(Token::SUB, overwrite); | 3117 GenericUnaryOpStub stub(Token::SUB, overwrite); |
3118 Result operand = frame_->Pop(); | 3118 Result operand = frame_->Pop(); |
3119 Result answer = frame_->CallStub(&stub, &operand); | 3119 Result answer = frame_->CallStub(&stub, &operand); |
| 3120 answer.set_type_info(TypeInfo::Number()); |
3120 frame_->Push(&answer); | 3121 frame_->Push(&answer); |
3121 break; | 3122 break; |
3122 } | 3123 } |
3123 | 3124 |
3124 case Token::BIT_NOT: { | 3125 case Token::BIT_NOT: { |
3125 // Smi check. | 3126 // Smi check. |
3126 JumpTarget smi_label; | 3127 JumpTarget smi_label; |
3127 JumpTarget continue_label; | 3128 JumpTarget continue_label; |
3128 Result operand = frame_->Pop(); | 3129 Result operand = frame_->Pop(); |
3129 operand.ToRegister(); | 3130 operand.ToRegister(); |
3130 | 3131 |
3131 Condition is_smi = masm_->CheckSmi(operand.reg()); | 3132 Condition is_smi = masm_->CheckSmi(operand.reg()); |
3132 smi_label.Branch(is_smi, &operand); | 3133 smi_label.Branch(is_smi, &operand); |
3133 | 3134 |
3134 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); | 3135 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite); |
3135 Result answer = frame_->CallStub(&stub, &operand); | 3136 Result answer = frame_->CallStub(&stub, &operand); |
3136 continue_label.Jump(&answer); | 3137 continue_label.Jump(&answer); |
3137 | 3138 |
3138 smi_label.Bind(&answer); | 3139 smi_label.Bind(&answer); |
3139 answer.ToRegister(); | 3140 answer.ToRegister(); |
3140 frame_->Spill(answer.reg()); | 3141 frame_->Spill(answer.reg()); |
3141 __ SmiNot(answer.reg(), answer.reg()); | 3142 __ SmiNot(answer.reg(), answer.reg()); |
3142 continue_label.Bind(&answer); | 3143 continue_label.Bind(&answer); |
| 3144 answer.set_type_info(TypeInfo::Smi()); |
3143 frame_->Push(&answer); | 3145 frame_->Push(&answer); |
3144 break; | 3146 break; |
3145 } | 3147 } |
3146 | 3148 |
3147 case Token::ADD: { | 3149 case Token::ADD: { |
3148 // Smi check. | 3150 // Smi check. |
3149 JumpTarget continue_label; | 3151 JumpTarget continue_label; |
3150 Result operand = frame_->Pop(); | 3152 Result operand = frame_->Pop(); |
| 3153 TypeInfo operand_info = operand.type_info(); |
3151 operand.ToRegister(); | 3154 operand.ToRegister(); |
3152 Condition is_smi = masm_->CheckSmi(operand.reg()); | 3155 Condition is_smi = masm_->CheckSmi(operand.reg()); |
3153 continue_label.Branch(is_smi, &operand); | 3156 continue_label.Branch(is_smi, &operand); |
3154 frame_->Push(&operand); | 3157 frame_->Push(&operand); |
3155 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, | 3158 Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER, |
3156 CALL_FUNCTION, 1); | 3159 CALL_FUNCTION, 1); |
3157 | 3160 |
3158 continue_label.Bind(&answer); | 3161 continue_label.Bind(&answer); |
| 3162 if (operand_info.IsSmi()) { |
| 3163 answer.set_type_info(TypeInfo::Smi()); |
| 3164 } else if (operand_info.IsInteger32()) { |
| 3165 answer.set_type_info(TypeInfo::Integer32()); |
| 3166 } else { |
| 3167 answer.set_type_info(TypeInfo::Number()); |
| 3168 } |
3159 frame_->Push(&answer); | 3169 frame_->Push(&answer); |
3160 break; | 3170 break; |
3161 } | 3171 } |
3162 | |
3163 default: | 3172 default: |
3164 UNREACHABLE(); | 3173 UNREACHABLE(); |
3165 } | 3174 } |
3166 } | 3175 } |
3167 } | 3176 } |
3168 | 3177 |
3169 | 3178 |
3170 // The value in dst was optimistically incremented or decremented. | 3179 // The value in dst was optimistically incremented or decremented. |
3171 // The result overflowed or was not smi tagged. Call into the runtime | 3180 // The result overflowed or was not smi tagged. Call into the runtime |
3172 // to convert the argument to a number, and call the specialized add | 3181 // to convert the argument to a number, and call the specialized add |
(...skipping 2540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5713 }; | 5722 }; |
5714 | 5723 |
5715 | 5724 |
5716 void DeferredInlineBinaryOperation::Generate() { | 5725 void DeferredInlineBinaryOperation::Generate() { |
5717 GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB); | 5726 GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB); |
5718 stub.GenerateCall(masm_, left_, right_); | 5727 stub.GenerateCall(masm_, left_, right_); |
5719 if (!dst_.is(rax)) __ movq(dst_, rax); | 5728 if (!dst_.is(rax)) __ movq(dst_, rax); |
5720 } | 5729 } |
5721 | 5730 |
5722 | 5731 |
| 5732 static TypeInfo CalculateTypeInfo(TypeInfo operands_type, |
| 5733 Token::Value op, |
| 5734 const Result& right, |
| 5735 const Result& left) { |
| 5736 // Set TypeInfo of result according to the operation performed. |
| 5737 // We rely on the fact that smis have a 32 bit payload on x64. |
| 5738 STATIC_ASSERT(kSmiValueSize == 32); |
| 5739 switch (op) { |
| 5740 case Token::COMMA: |
| 5741 return right.type_info(); |
| 5742 case Token::OR: |
| 5743 case Token::AND: |
| 5744 // Result type can be either of the two input types. |
| 5745 return operands_type; |
| 5746 case Token::BIT_OR: |
| 5747 case Token::BIT_XOR: |
| 5748 case Token::BIT_AND: |
| 5749 // Result is always a smi. |
| 5750 return TypeInfo::Smi(); |
| 5751 case Token::SAR: |
| 5752 case Token::SHL: |
| 5753 // Result is always a smi. |
| 5754 return TypeInfo::Smi(); |
| 5755 case Token::SHR: |
| 5756 // Result of x >>> y is always a smi if masked y >= 1, otherwise a number. |
| 5757 return (right.is_constant() && right.handle()->IsSmi() |
| 5758 && (Smi::cast(*right.handle())->value() & 0x1F) >= 1) |
| 5759 ? TypeInfo::Smi() |
| 5760 : TypeInfo::Number(); |
| 5761 case Token::ADD: |
| 5762 if (operands_type.IsNumber()) { |
| 5763 return TypeInfo::Number(); |
| 5764 } else if (left.type_info().IsString() || right.type_info().IsString()) { |
| 5765 return TypeInfo::String(); |
| 5766 } else { |
| 5767 return TypeInfo::Unknown(); |
| 5768 } |
| 5769 case Token::SUB: |
| 5770 case Token::MUL: |
| 5771 case Token::DIV: |
| 5772 case Token::MOD: |
| 5773 // Result is always a number. |
| 5774 return TypeInfo::Number(); |
| 5775 default: |
| 5776 UNREACHABLE(); |
| 5777 } |
| 5778 UNREACHABLE(); |
| 5779 return TypeInfo::Unknown(); |
| 5780 } |
| 5781 |
| 5782 |
5723 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 5783 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
5724 StaticType* type, | 5784 StaticType* type, |
5725 OverwriteMode overwrite_mode) { | 5785 OverwriteMode overwrite_mode) { |
5726 Comment cmnt(masm_, "[ BinaryOperation"); | 5786 Comment cmnt(masm_, "[ BinaryOperation"); |
5727 Comment cmnt_token(masm_, Token::String(op)); | 5787 Comment cmnt_token(masm_, Token::String(op)); |
5728 | 5788 |
5729 if (op == Token::COMMA) { | 5789 if (op == Token::COMMA) { |
5730 // Simply discard left value. | 5790 // Simply discard left value. |
5731 frame_->Nip(1); | 5791 frame_->Nip(1); |
5732 return; | 5792 return; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5778 // Compute the constant result at compile time, and leave it on the frame. | 5838 // Compute the constant result at compile time, and leave it on the frame. |
5779 int left_int = Smi::cast(*left.handle())->value(); | 5839 int left_int = Smi::cast(*left.handle())->value(); |
5780 int right_int = Smi::cast(*right.handle())->value(); | 5840 int right_int = Smi::cast(*right.handle())->value(); |
5781 if (FoldConstantSmis(op, left_int, right_int)) return; | 5841 if (FoldConstantSmis(op, left_int, right_int)) return; |
5782 } | 5842 } |
5783 | 5843 |
5784 // Get number type of left and right sub-expressions. | 5844 // Get number type of left and right sub-expressions. |
5785 TypeInfo operands_type = | 5845 TypeInfo operands_type = |
5786 TypeInfo::Combine(left.type_info(), right.type_info()); | 5846 TypeInfo::Combine(left.type_info(), right.type_info()); |
5787 | 5847 |
| 5848 TypeInfo result_type = CalculateTypeInfo(operands_type, op, right, left); |
| 5849 |
5788 Result answer; | 5850 Result answer; |
5789 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 5851 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
5790 GenericBinaryOpStub stub(op, | 5852 GenericBinaryOpStub stub(op, |
5791 overwrite_mode, | 5853 overwrite_mode, |
5792 NO_SMI_CODE_IN_STUB, | 5854 NO_SMI_CODE_IN_STUB, |
5793 operands_type); | 5855 operands_type); |
5794 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 5856 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
5795 } else if (right_is_smi_constant) { | 5857 } else if (right_is_smi_constant) { |
5796 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), | 5858 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
5797 type, false, overwrite_mode); | 5859 type, false, overwrite_mode); |
(...skipping 10 matching lines...) Expand all Loading... |
5808 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 5870 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
5809 } else { | 5871 } else { |
5810 GenericBinaryOpStub stub(op, | 5872 GenericBinaryOpStub stub(op, |
5811 overwrite_mode, | 5873 overwrite_mode, |
5812 NO_GENERIC_BINARY_FLAGS, | 5874 NO_GENERIC_BINARY_FLAGS, |
5813 operands_type); | 5875 operands_type); |
5814 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 5876 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
5815 } | 5877 } |
5816 } | 5878 } |
5817 | 5879 |
5818 // Set TypeInfo of result according to the operation performed. | |
5819 // We rely on the fact that smis have a 32 bit payload on x64. | |
5820 ASSERT(kSmiValueSize == 32); | |
5821 TypeInfo result_type = TypeInfo::Unknown(); | |
5822 switch (op) { | |
5823 case Token::COMMA: | |
5824 result_type = right.type_info(); | |
5825 break; | |
5826 case Token::OR: | |
5827 case Token::AND: | |
5828 // Result type can be either of the two input types. | |
5829 result_type = operands_type; | |
5830 break; | |
5831 case Token::BIT_OR: | |
5832 case Token::BIT_XOR: | |
5833 case Token::BIT_AND: | |
5834 // Result is always a smi. | |
5835 result_type = TypeInfo::Smi(); | |
5836 break; | |
5837 case Token::SAR: | |
5838 case Token::SHL: | |
5839 // Result is always a smi. | |
5840 result_type = TypeInfo::Smi(); | |
5841 break; | |
5842 case Token::SHR: | |
5843 // Result of x >>> y is always a smi if masked y >= 1, otherwise a number. | |
5844 result_type = (right.is_constant() && right.handle()->IsSmi() | |
5845 && (Smi::cast(*right.handle())->value() & 0x1F) >= 1) | |
5846 ? TypeInfo::Smi() | |
5847 : TypeInfo::Number(); | |
5848 break; | |
5849 case Token::ADD: | |
5850 if (operands_type.IsNumber()) { | |
5851 result_type = TypeInfo::Number(); | |
5852 } else if (operands_type.IsString()) { | |
5853 result_type = TypeInfo::String(); | |
5854 } else { | |
5855 result_type = TypeInfo::Unknown(); | |
5856 } | |
5857 break; | |
5858 case Token::SUB: | |
5859 case Token::MUL: | |
5860 case Token::DIV: | |
5861 case Token::MOD: | |
5862 // Result is always a number. | |
5863 result_type = TypeInfo::Number(); | |
5864 break; | |
5865 default: | |
5866 UNREACHABLE(); | |
5867 } | |
5868 answer.set_type_info(result_type); | 5880 answer.set_type_info(result_type); |
5869 frame_->Push(&answer); | 5881 frame_->Push(&answer); |
5870 } | 5882 } |
5871 | 5883 |
5872 | 5884 |
5873 // Emit a LoadIC call to get the value from receiver and leave it in | 5885 // Emit a LoadIC call to get the value from receiver and leave it in |
5874 // dst. The receiver register is restored after the call. | 5886 // dst. The receiver register is restored after the call. |
5875 class DeferredReferenceGetNamedValue: public DeferredCode { | 5887 class DeferredReferenceGetNamedValue: public DeferredCode { |
5876 public: | 5888 public: |
5877 DeferredReferenceGetNamedValue(Register dst, | 5889 DeferredReferenceGetNamedValue(Register dst, |
(...skipping 4589 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10467 // Call the function from C++. | 10479 // Call the function from C++. |
10468 return FUNCTION_CAST<ModuloFunction>(buffer); | 10480 return FUNCTION_CAST<ModuloFunction>(buffer); |
10469 } | 10481 } |
10470 | 10482 |
10471 #endif | 10483 #endif |
10472 | 10484 |
10473 | 10485 |
10474 #undef __ | 10486 #undef __ |
10475 | 10487 |
10476 } } // namespace v8::internal | 10488 } } // namespace v8::internal |
OLD | NEW |