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 822 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
833 const char* op_name = Token::Name(op_); | 833 const char* op_name = Token::Name(op_); |
834 const char* overwrite_name; | 834 const char* overwrite_name; |
835 switch (mode_) { | 835 switch (mode_) { |
836 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 836 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
837 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 837 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
838 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 838 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
839 default: overwrite_name = "UnknownOverwrite"; break; | 839 default: overwrite_name = "UnknownOverwrite"; break; |
840 } | 840 } |
841 | 841 |
842 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 842 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
843 "GenericBinaryOpStub_%s_%s%s_%s%s%s", | 843 "GenericBinaryOpStub_%s_%s%s_%s%s_%s", |
844 op_name, | 844 op_name, |
845 overwrite_name, | 845 overwrite_name, |
846 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 846 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
847 args_in_registers_ ? "RegArgs" : "StackArgs", | 847 args_in_registers_ ? "RegArgs" : "StackArgs", |
848 args_reversed_ ? "_R" : "", | 848 args_reversed_ ? "_R" : "", |
849 only_numbers_in_stub_ ? "_OnlyNumbers" : ""); | 849 NumberInfo::ToString(operands_type_)); |
850 return name_; | 850 return name_; |
851 } | 851 } |
852 | 852 |
853 | 853 |
854 // Call the specialized stub for a binary operation. | 854 // Call the specialized stub for a binary operation. |
855 class DeferredInlineBinaryOperation: public DeferredCode { | 855 class DeferredInlineBinaryOperation: public DeferredCode { |
856 public: | 856 public: |
857 DeferredInlineBinaryOperation(Token::Value op, | 857 DeferredInlineBinaryOperation(Token::Value op, |
858 Register dst, | 858 Register dst, |
859 Register left, | 859 Register left, |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 right.is_constant() && !right.handle()->IsSmi(); | 1003 right.is_constant() && !right.handle()->IsSmi(); |
1004 | 1004 |
1005 if (left_is_smi_constant && right_is_smi_constant) { | 1005 if (left_is_smi_constant && right_is_smi_constant) { |
1006 // Compute the constant result at compile time, and leave it on the frame. | 1006 // Compute the constant result at compile time, and leave it on the frame. |
1007 int left_int = Smi::cast(*left.handle())->value(); | 1007 int left_int = Smi::cast(*left.handle())->value(); |
1008 int right_int = Smi::cast(*right.handle())->value(); | 1008 int right_int = Smi::cast(*right.handle())->value(); |
1009 if (FoldConstantSmis(op, left_int, right_int)) return; | 1009 if (FoldConstantSmis(op, left_int, right_int)) return; |
1010 } | 1010 } |
1011 | 1011 |
1012 // Get number type of left and right sub-expressions. | 1012 // Get number type of left and right sub-expressions. |
1013 bool only_numbers = left.is_number() && right.is_number(); | 1013 NumberInfo::Type operands_type = |
1014 bool only_smis = left.is_smi() && right.is_smi(); | 1014 NumberInfo::Combine(left.number_info(), right.number_info()); |
1015 | 1015 |
1016 Result answer; | 1016 Result answer; |
1017 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 1017 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
1018 // Go straight to the slow case, with no smi code. | 1018 // Go straight to the slow case, with no smi code. |
1019 GenericBinaryOpStub stub(op, | 1019 GenericBinaryOpStub stub(op, |
1020 overwrite_mode, | 1020 overwrite_mode, |
1021 NO_SMI_CODE_IN_STUB, | 1021 NO_SMI_CODE_IN_STUB, |
1022 only_numbers); | 1022 operands_type); |
1023 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1023 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
1024 } else if (right_is_smi_constant) { | 1024 } else if (right_is_smi_constant) { |
1025 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), | 1025 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
1026 type, false, overwrite_mode); | 1026 type, false, overwrite_mode); |
1027 } else if (left_is_smi_constant) { | 1027 } else if (left_is_smi_constant) { |
1028 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), | 1028 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
1029 type, true, overwrite_mode); | 1029 type, true, overwrite_mode); |
1030 } else { | 1030 } else { |
1031 // Set the flags based on the operation, type and loop nesting level. | 1031 // Set the flags based on the operation, type and loop nesting level. |
1032 // Bit operations always assume they likely operate on Smis. Still only | 1032 // Bit operations always assume they likely operate on Smis. Still only |
1033 // generate the inline Smi check code if this operation is part of a loop. | 1033 // generate the inline Smi check code if this operation is part of a loop. |
1034 // For all other operations only inline the Smi check code for likely smis | 1034 // For all other operations only inline the Smi check code for likely smis |
1035 // if the operation is part of a loop. | 1035 // if the operation is part of a loop. |
1036 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { | 1036 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { |
1037 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 1037 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
1038 } else { | 1038 } else { |
1039 GenericBinaryOpStub stub(op, | 1039 GenericBinaryOpStub stub(op, |
1040 overwrite_mode, | 1040 overwrite_mode, |
1041 NO_GENERIC_BINARY_FLAGS, | 1041 NO_GENERIC_BINARY_FLAGS, |
1042 only_numbers); | 1042 operands_type); |
1043 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1043 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
1044 } | 1044 } |
1045 } | 1045 } |
1046 | 1046 |
1047 // Set NumberInfo of result according to the operation performed. | 1047 // Set NumberInfo of result according to the operation performed. |
1048 NumberInfo::Type info = NumberInfo::kUnknown; | 1048 // Rely on the fact that smis have a 31 bit payload on ia32. |
| 1049 ASSERT(kSmiValueSize == 31); |
| 1050 NumberInfo::Type result_type = NumberInfo::kUnknown; |
1049 switch (op) { | 1051 switch (op) { |
1050 case Token::COMMA: | 1052 case Token::COMMA: |
1051 info = right.number_info(); | 1053 result_type = right.number_info(); |
| 1054 break; |
1052 case Token::OR: | 1055 case Token::OR: |
1053 case Token::AND: | 1056 case Token::AND: |
1054 // Could be anything. Check inputs. | 1057 // Result type can be either of the two input types. |
1055 if (only_numbers) | 1058 result_type = operands_type; |
1056 info = NumberInfo::kNumber; | |
1057 break; | 1059 break; |
1058 case Token::BIT_OR: | 1060 case Token::BIT_OR: |
1059 case Token::BIT_XOR: | 1061 case Token::BIT_XOR: |
1060 case Token::BIT_AND: | 1062 case Token::BIT_AND: |
| 1063 // Result is always a number. Smi property of inputs is preserved. |
| 1064 result_type = (operands_type == NumberInfo::kSmi) |
| 1065 ? NumberInfo::kSmi |
| 1066 : NumberInfo::kNumber; |
| 1067 break; |
1061 case Token::SAR: | 1068 case Token::SAR: |
| 1069 // Result is a smi if we shift by a constant >= 1, otherwise a number. |
| 1070 result_type = (right.is_constant() && right.handle()->IsSmi() |
| 1071 && Smi::cast(*right.handle())->value() >= 1) |
| 1072 ? NumberInfo::kSmi |
| 1073 : NumberInfo::kNumber; |
| 1074 break; |
1062 case Token::SHR: | 1075 case Token::SHR: |
1063 info = only_smis ? NumberInfo::kSmi : NumberInfo::kNumber; | 1076 // Result is a smi if we shift by a constant >= 2, otherwise a number. |
| 1077 result_type = (right.is_constant() && right.handle()->IsSmi() |
| 1078 && Smi::cast(*right.handle())->value() >= 2) |
| 1079 ? NumberInfo::kSmi |
| 1080 : NumberInfo::kNumber; |
| 1081 break; |
| 1082 case Token::ADD: |
| 1083 // Result could be a string or a number. Check types of inputs. |
| 1084 result_type = NumberInfo::IsNumber(operands_type) |
| 1085 ? NumberInfo::kNumber |
| 1086 : NumberInfo::kUnknown; |
1064 break; | 1087 break; |
1065 case Token::SHL: | 1088 case Token::SHL: |
1066 info = NumberInfo::kNumber; | |
1067 break; | |
1068 case Token::ADD: | |
1069 // Could be strings or numbers. Check types of inputs. | |
1070 if (only_numbers) info = NumberInfo::kNumber; | |
1071 break; | |
1072 case Token::SUB: | 1089 case Token::SUB: |
1073 case Token::MUL: | 1090 case Token::MUL: |
1074 case Token::DIV: | 1091 case Token::DIV: |
1075 case Token::MOD: | 1092 case Token::MOD: |
1076 info = NumberInfo::kNumber; | 1093 // Result is always a number. |
| 1094 result_type = NumberInfo::kNumber; |
1077 break; | 1095 break; |
1078 default: | 1096 default: |
1079 UNREACHABLE(); | 1097 UNREACHABLE(); |
1080 } | 1098 } |
1081 answer.set_number_info(info); | 1099 answer.set_number_info(result_type); |
1082 frame_->Push(&answer); | 1100 frame_->Push(&answer); |
1083 } | 1101 } |
1084 | 1102 |
1085 | 1103 |
1086 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 1104 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
1087 Object* answer_object = Heap::undefined_value(); | 1105 Object* answer_object = Heap::undefined_value(); |
1088 switch (op) { | 1106 switch (op) { |
1089 case Token::ADD: | 1107 case Token::ADD: |
1090 if (Smi::IsValid(left + right)) { | 1108 if (Smi::IsValid(left + right)) { |
1091 answer_object = Smi::FromInt(left + right); | 1109 answer_object = Smi::FromInt(left + right); |
(...skipping 6517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7609 } | 7627 } |
7610 | 7628 |
7611 // Floating point case. | 7629 // Floating point case. |
7612 switch (op_) { | 7630 switch (op_) { |
7613 case Token::ADD: | 7631 case Token::ADD: |
7614 case Token::SUB: | 7632 case Token::SUB: |
7615 case Token::MUL: | 7633 case Token::MUL: |
7616 case Token::DIV: { | 7634 case Token::DIV: { |
7617 if (CpuFeatures::IsSupported(SSE2)) { | 7635 if (CpuFeatures::IsSupported(SSE2)) { |
7618 CpuFeatures::Scope use_sse2(SSE2); | 7636 CpuFeatures::Scope use_sse2(SSE2); |
7619 if (only_numbers_in_stub_) { | 7637 if (NumberInfo::IsNumber(operands_type_)) { |
7620 if (FLAG_debug_code) { | 7638 if (FLAG_debug_code) { |
7621 // Assert at runtime that inputs are only numbers. | 7639 // Assert at runtime that inputs are only numbers. |
7622 __ AbortIfNotNumber(edx, | 7640 __ AbortIfNotNumber(edx, |
7623 "GenericBinaryOpStub operand not a number."); | 7641 "GenericBinaryOpStub operand not a number."); |
7624 __ AbortIfNotNumber(eax, | 7642 __ AbortIfNotNumber(eax, |
7625 "GenericBinaryOpStub operand not a number."); | 7643 "GenericBinaryOpStub operand not a number."); |
7626 } | 7644 } |
7627 FloatingPointHelper::LoadSSE2Operands(masm); | 7645 FloatingPointHelper::LoadSSE2Operands(masm); |
7628 } else { | 7646 } else { |
7629 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); | 7647 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); |
7630 } | 7648 } |
7631 | 7649 |
7632 switch (op_) { | 7650 switch (op_) { |
7633 case Token::ADD: __ addsd(xmm0, xmm1); break; | 7651 case Token::ADD: __ addsd(xmm0, xmm1); break; |
7634 case Token::SUB: __ subsd(xmm0, xmm1); break; | 7652 case Token::SUB: __ subsd(xmm0, xmm1); break; |
7635 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 7653 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
7636 case Token::DIV: __ divsd(xmm0, xmm1); break; | 7654 case Token::DIV: __ divsd(xmm0, xmm1); break; |
7637 default: UNREACHABLE(); | 7655 default: UNREACHABLE(); |
7638 } | 7656 } |
7639 GenerateHeapResultAllocation(masm, &call_runtime); | 7657 GenerateHeapResultAllocation(masm, &call_runtime); |
7640 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 7658 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
7641 GenerateReturn(masm); | 7659 GenerateReturn(masm); |
7642 } else { // SSE2 not available, use FPU. | 7660 } else { // SSE2 not available, use FPU. |
7643 if (only_numbers_in_stub_) { | 7661 if (NumberInfo::IsNumber(operands_type_)) { |
7644 if (FLAG_debug_code) { | 7662 if (FLAG_debug_code) { |
7645 // Assert at runtime that inputs are only numbers. | 7663 // Assert at runtime that inputs are only numbers. |
7646 __ AbortIfNotNumber(edx, | 7664 __ AbortIfNotNumber(edx, |
7647 "GenericBinaryOpStub operand not a number."); | 7665 "GenericBinaryOpStub operand not a number."); |
7648 __ AbortIfNotNumber(eax, | 7666 __ AbortIfNotNumber(eax, |
7649 "GenericBinaryOpStub operand not a number."); | 7667 "GenericBinaryOpStub operand not a number."); |
7650 } | 7668 } |
7651 } else { | 7669 } else { |
7652 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 7670 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
7653 } | 7671 } |
(...skipping 2892 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10546 | 10564 |
10547 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 10565 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
10548 // tagged as a small integer. | 10566 // tagged as a small integer. |
10549 __ bind(&runtime); | 10567 __ bind(&runtime); |
10550 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 10568 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); |
10551 } | 10569 } |
10552 | 10570 |
10553 #undef __ | 10571 #undef __ |
10554 | 10572 |
10555 } } // namespace v8::internal | 10573 } } // namespace v8::internal |
OLD | NEW |