| 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 21 matching lines...) Expand all Loading... |
| 32 #include "compiler.h" | 32 #include "compiler.h" |
| 33 #include "debug.h" | 33 #include "debug.h" |
| 34 #include "ic-inl.h" | 34 #include "ic-inl.h" |
| 35 #include "jsregexp.h" | 35 #include "jsregexp.h" |
| 36 #include "parser.h" | 36 #include "parser.h" |
| 37 #include "regexp-macro-assembler.h" | 37 #include "regexp-macro-assembler.h" |
| 38 #include "regexp-stack.h" | 38 #include "regexp-stack.h" |
| 39 #include "register-allocator-inl.h" | 39 #include "register-allocator-inl.h" |
| 40 #include "runtime.h" | 40 #include "runtime.h" |
| 41 #include "scopes.h" | 41 #include "scopes.h" |
| 42 #include "virtual-frame-inl.h" |
| 42 | 43 |
| 43 namespace v8 { | 44 namespace v8 { |
| 44 namespace internal { | 45 namespace internal { |
| 45 | 46 |
| 46 #define __ ACCESS_MASM(masm_) | 47 #define __ ACCESS_MASM(masm_) |
| 47 | 48 |
| 48 // ------------------------------------------------------------------------- | 49 // ------------------------------------------------------------------------- |
| 49 // Platform-specific DeferredCode functions. | 50 // Platform-specific DeferredCode functions. |
| 50 | 51 |
| 51 void DeferredCode::SaveRegisters() { | 52 void DeferredCode::SaveRegisters() { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 info_(NULL), | 110 info_(NULL), |
| 110 frame_(NULL), | 111 frame_(NULL), |
| 111 allocator_(NULL), | 112 allocator_(NULL), |
| 112 state_(NULL), | 113 state_(NULL), |
| 113 loop_nesting_(0), | 114 loop_nesting_(0), |
| 114 function_return_is_shadowed_(false), | 115 function_return_is_shadowed_(false), |
| 115 in_spilled_code_(false) { | 116 in_spilled_code_(false) { |
| 116 } | 117 } |
| 117 | 118 |
| 118 | 119 |
| 119 Scope* CodeGenerator::scope() { return info_->function()->scope(); } | |
| 120 | |
| 121 | |
| 122 // Calling conventions: | 120 // Calling conventions: |
| 123 // ebp: caller's frame pointer | 121 // ebp: caller's frame pointer |
| 124 // esp: stack pointer | 122 // esp: stack pointer |
| 125 // edi: called JS function | 123 // edi: called JS function |
| 126 // esi: callee's context | 124 // esi: callee's context |
| 127 | 125 |
| 128 void CodeGenerator::Generate(CompilationInfo* info) { | 126 void CodeGenerator::Generate(CompilationInfo* info) { |
| 129 // Record the position for debugging purposes. | 127 // Record the position for debugging purposes. |
| 130 CodeForFunctionPosition(info->function()); | 128 CodeForFunctionPosition(info->function()); |
| 129 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); |
| 131 | 130 |
| 132 // Initialize state. | 131 // Initialize state. |
| 133 info_ = info; | 132 info_ = info; |
| 134 ASSERT(allocator_ == NULL); | 133 ASSERT(allocator_ == NULL); |
| 135 RegisterAllocator register_allocator(this); | 134 RegisterAllocator register_allocator(this); |
| 136 allocator_ = ®ister_allocator; | 135 allocator_ = ®ister_allocator; |
| 137 ASSERT(frame_ == NULL); | 136 ASSERT(frame_ == NULL); |
| 138 frame_ = new VirtualFrame(); | 137 frame_ = new VirtualFrame(); |
| 139 set_in_spilled_code(false); | 138 set_in_spilled_code(false); |
| 140 | 139 |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 726 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
| 728 // convert it to a boolean in the condition code register or jump to | 727 // convert it to a boolean in the condition code register or jump to |
| 729 // 'false_target'/'true_target' as appropriate. | 728 // 'false_target'/'true_target' as appropriate. |
| 730 void CodeGenerator::ToBoolean(ControlDestination* dest) { | 729 void CodeGenerator::ToBoolean(ControlDestination* dest) { |
| 731 Comment cmnt(masm_, "[ ToBoolean"); | 730 Comment cmnt(masm_, "[ ToBoolean"); |
| 732 | 731 |
| 733 // The value to convert should be popped from the frame. | 732 // The value to convert should be popped from the frame. |
| 734 Result value = frame_->Pop(); | 733 Result value = frame_->Pop(); |
| 735 value.ToRegister(); | 734 value.ToRegister(); |
| 736 | 735 |
| 737 if (value.is_number()) { | 736 if (value.is_integer32()) { // Also takes Smi case. |
| 737 Comment cmnt(masm_, "ONLY_INTEGER_32"); |
| 738 if (FLAG_debug_code) { |
| 739 Label ok; |
| 740 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); |
| 741 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 742 __ j(zero, &ok); |
| 743 __ fldz(); |
| 744 __ fld_d(FieldOperand(value.reg(), HeapNumber::kValueOffset)); |
| 745 __ FCmp(); |
| 746 __ j(not_zero, &ok); |
| 747 __ Abort("Smi was wrapped in HeapNumber in output from bitop"); |
| 748 __ bind(&ok); |
| 749 } |
| 750 // In the integer32 case there are no Smis hidden in heap numbers, so we |
| 751 // need only test for Smi zero. |
| 752 __ test(value.reg(), Operand(value.reg())); |
| 753 dest->false_target()->Branch(zero); |
| 754 value.Unuse(); |
| 755 dest->Split(not_zero); |
| 756 } else if (value.is_number()) { |
| 738 Comment cmnt(masm_, "ONLY_NUMBER"); | 757 Comment cmnt(masm_, "ONLY_NUMBER"); |
| 739 // Fast case if NumberInfo indicates only numbers. | 758 // Fast case if NumberInfo indicates only numbers. |
| 740 if (FLAG_debug_code) { | 759 if (FLAG_debug_code) { |
| 741 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); | 760 __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number."); |
| 742 } | 761 } |
| 743 // Smi => false iff zero. | 762 // Smi => false iff zero. |
| 744 ASSERT(kSmiTag == 0); | 763 ASSERT(kSmiTag == 0); |
| 745 __ test(value.reg(), Operand(value.reg())); | 764 __ test(value.reg(), Operand(value.reg())); |
| 746 dest->false_target()->Branch(zero); | 765 dest->false_target()->Branch(zero); |
| 747 __ test(value.reg(), Immediate(kSmiTagMask)); | 766 __ test(value.reg(), Immediate(kSmiTagMask)); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 811 | 830 |
| 812 // Test if operands are smi or number objects (fp). Requirements: | 831 // Test if operands are smi or number objects (fp). Requirements: |
| 813 // operand_1 in eax, operand_2 in edx; falls through on float | 832 // operand_1 in eax, operand_2 in edx; falls through on float |
| 814 // operands, jumps to the non_float label otherwise. | 833 // operands, jumps to the non_float label otherwise. |
| 815 static void CheckFloatOperands(MacroAssembler* masm, | 834 static void CheckFloatOperands(MacroAssembler* masm, |
| 816 Label* non_float, | 835 Label* non_float, |
| 817 Register scratch); | 836 Register scratch); |
| 818 // Takes the operands in edx and eax and loads them as integers in eax | 837 // Takes the operands in edx and eax and loads them as integers in eax |
| 819 // and ecx. | 838 // and ecx. |
| 820 static void LoadAsIntegers(MacroAssembler* masm, | 839 static void LoadAsIntegers(MacroAssembler* masm, |
| 840 NumberInfo number_info, |
| 821 bool use_sse3, | 841 bool use_sse3, |
| 822 Label* operand_conversion_failure); | 842 Label* operand_conversion_failure); |
| 843 static void LoadNumbersAsIntegers(MacroAssembler* masm, |
| 844 NumberInfo number_info, |
| 845 bool use_sse3, |
| 846 Label* operand_conversion_failure); |
| 847 static void LoadUnknownsAsIntegers(MacroAssembler* masm, |
| 848 bool use_sse3, |
| 849 Label* operand_conversion_failure); |
| 850 |
| 823 // Test if operands are smis or heap numbers and load them | 851 // Test if operands are smis or heap numbers and load them |
| 824 // into xmm0 and xmm1 if they are. Operands are in edx and eax. | 852 // into xmm0 and xmm1 if they are. Operands are in edx and eax. |
| 825 // Leaves operands unchanged. | 853 // Leaves operands unchanged. |
| 826 static void LoadSSE2Operands(MacroAssembler* masm); | 854 static void LoadSSE2Operands(MacroAssembler* masm); |
| 827 // Test if operands are numbers (smi or HeapNumber objects), and load | 855 // Test if operands are numbers (smi or HeapNumber objects), and load |
| 828 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if | 856 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if |
| 829 // either operand is not a number. Operands are in edx and eax. | 857 // either operand is not a number. Operands are in edx and eax. |
| 830 // Leaves operands unchanged. | 858 // Leaves operands unchanged. |
| 831 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); | 859 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); |
| 832 | 860 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 844 const char* op_name = Token::Name(op_); | 872 const char* op_name = Token::Name(op_); |
| 845 const char* overwrite_name; | 873 const char* overwrite_name; |
| 846 switch (mode_) { | 874 switch (mode_) { |
| 847 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 875 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 848 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 876 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 849 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 877 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 850 default: overwrite_name = "UnknownOverwrite"; break; | 878 default: overwrite_name = "UnknownOverwrite"; break; |
| 851 } | 879 } |
| 852 | 880 |
| 853 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 881 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 854 "GenericBinaryOpStub_%s_%s%s_%s%s_%s", | 882 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", |
| 855 op_name, | 883 op_name, |
| 856 overwrite_name, | 884 overwrite_name, |
| 857 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 885 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
| 858 args_in_registers_ ? "RegArgs" : "StackArgs", | 886 args_in_registers_ ? "RegArgs" : "StackArgs", |
| 859 args_reversed_ ? "_R" : "", | 887 args_reversed_ ? "_R" : "", |
| 860 NumberInfo::ToString(operands_type_)); | 888 static_operands_type_.ToString(), |
| 889 BinaryOpIC::GetName(runtime_operands_type_)); |
| 861 return name_; | 890 return name_; |
| 862 } | 891 } |
| 863 | 892 |
| 864 | 893 |
| 865 // Call the specialized stub for a binary operation. | 894 // Call the specialized stub for a binary operation. |
| 866 class DeferredInlineBinaryOperation: public DeferredCode { | 895 class DeferredInlineBinaryOperation: public DeferredCode { |
| 867 public: | 896 public: |
| 868 DeferredInlineBinaryOperation(Token::Value op, | 897 DeferredInlineBinaryOperation(Token::Value op, |
| 869 Register dst, | 898 Register dst, |
| 870 Register left, | 899 Register left, |
| 871 Register right, | 900 Register right, |
| 901 NumberInfo left_info, |
| 902 NumberInfo right_info, |
| 872 OverwriteMode mode) | 903 OverwriteMode mode) |
| 873 : op_(op), dst_(dst), left_(left), right_(right), mode_(mode) { | 904 : op_(op), dst_(dst), left_(left), right_(right), |
| 905 left_info_(left_info), right_info_(right_info), mode_(mode) { |
| 874 set_comment("[ DeferredInlineBinaryOperation"); | 906 set_comment("[ DeferredInlineBinaryOperation"); |
| 875 } | 907 } |
| 876 | 908 |
| 877 virtual void Generate(); | 909 virtual void Generate(); |
| 878 | 910 |
| 879 private: | 911 private: |
| 880 Token::Value op_; | 912 Token::Value op_; |
| 881 Register dst_; | 913 Register dst_; |
| 882 Register left_; | 914 Register left_; |
| 883 Register right_; | 915 Register right_; |
| 916 NumberInfo left_info_; |
| 917 NumberInfo right_info_; |
| 884 OverwriteMode mode_; | 918 OverwriteMode mode_; |
| 885 }; | 919 }; |
| 886 | 920 |
| 887 | 921 |
| 888 void DeferredInlineBinaryOperation::Generate() { | 922 void DeferredInlineBinaryOperation::Generate() { |
| 889 Label done; | 923 Label done; |
| 890 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || | 924 if (CpuFeatures::IsSupported(SSE2) && ((op_ == Token::ADD) || |
| 891 (op_ ==Token::SUB) || | 925 (op_ ==Token::SUB) || |
| 892 (op_ == Token::MUL) || | 926 (op_ == Token::MUL) || |
| 893 (op_ == Token::DIV))) { | 927 (op_ == Token::DIV))) { |
| 894 CpuFeatures::Scope use_sse2(SSE2); | 928 CpuFeatures::Scope use_sse2(SSE2); |
| 895 Label call_runtime, after_alloc_failure; | 929 Label call_runtime, after_alloc_failure; |
| 896 Label left_smi, right_smi, load_right, do_op; | 930 Label left_smi, right_smi, load_right, do_op; |
| 897 __ test(left_, Immediate(kSmiTagMask)); | 931 if (!left_info_.IsSmi()) { |
| 898 __ j(zero, &left_smi); | 932 __ test(left_, Immediate(kSmiTagMask)); |
| 899 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), | 933 __ j(zero, &left_smi); |
| 900 Factory::heap_number_map()); | 934 if (!left_info_.IsNumber()) { |
| 901 __ j(not_equal, &call_runtime); | 935 __ cmp(FieldOperand(left_, HeapObject::kMapOffset), |
| 902 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); | 936 Factory::heap_number_map()); |
| 903 if (mode_ == OVERWRITE_LEFT) { | 937 __ j(not_equal, &call_runtime); |
| 904 __ mov(dst_, left_); | 938 } |
| 939 __ movdbl(xmm0, FieldOperand(left_, HeapNumber::kValueOffset)); |
| 940 if (mode_ == OVERWRITE_LEFT) { |
| 941 __ mov(dst_, left_); |
| 942 } |
| 943 __ jmp(&load_right); |
| 944 |
| 945 __ bind(&left_smi); |
| 905 } | 946 } |
| 906 __ jmp(&load_right); | |
| 907 | |
| 908 __ bind(&left_smi); | |
| 909 __ SmiUntag(left_); | 947 __ SmiUntag(left_); |
| 910 __ cvtsi2sd(xmm0, Operand(left_)); | 948 __ cvtsi2sd(xmm0, Operand(left_)); |
| 911 __ SmiTag(left_); | 949 __ SmiTag(left_); |
| 912 if (mode_ == OVERWRITE_LEFT) { | 950 if (mode_ == OVERWRITE_LEFT) { |
| 913 Label alloc_failure; | 951 Label alloc_failure; |
| 914 __ push(left_); | 952 __ push(left_); |
| 915 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 953 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 916 __ pop(left_); | 954 __ pop(left_); |
| 917 } | 955 } |
| 918 | 956 |
| 919 __ bind(&load_right); | 957 __ bind(&load_right); |
| 920 __ test(right_, Immediate(kSmiTagMask)); | 958 if (!right_info_.IsSmi()) { |
| 921 __ j(zero, &right_smi); | 959 __ test(right_, Immediate(kSmiTagMask)); |
| 922 __ cmp(FieldOperand(right_, HeapObject::kMapOffset), | 960 __ j(zero, &right_smi); |
| 923 Factory::heap_number_map()); | 961 if (!right_info_.IsNumber()) { |
| 924 __ j(not_equal, &call_runtime); | 962 __ cmp(FieldOperand(right_, HeapObject::kMapOffset), |
| 925 __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); | 963 Factory::heap_number_map()); |
| 926 if (mode_ == OVERWRITE_RIGHT) { | 964 __ j(not_equal, &call_runtime); |
| 927 __ mov(dst_, right_); | 965 } |
| 928 } else if (mode_ == NO_OVERWRITE) { | 966 __ movdbl(xmm1, FieldOperand(right_, HeapNumber::kValueOffset)); |
| 929 Label alloc_failure; | 967 if (mode_ == OVERWRITE_RIGHT) { |
| 930 __ push(left_); | 968 __ mov(dst_, right_); |
| 931 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 969 } else if (mode_ == NO_OVERWRITE) { |
| 932 __ pop(left_); | 970 Label alloc_failure; |
| 971 __ push(left_); |
| 972 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 973 __ pop(left_); |
| 974 } |
| 975 __ jmp(&do_op); |
| 976 |
| 977 __ bind(&right_smi); |
| 933 } | 978 } |
| 934 __ jmp(&do_op); | |
| 935 | |
| 936 __ bind(&right_smi); | |
| 937 __ SmiUntag(right_); | 979 __ SmiUntag(right_); |
| 938 __ cvtsi2sd(xmm1, Operand(right_)); | 980 __ cvtsi2sd(xmm1, Operand(right_)); |
| 939 __ SmiTag(right_); | 981 __ SmiTag(right_); |
| 940 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { | 982 if (mode_ == OVERWRITE_RIGHT || mode_ == NO_OVERWRITE) { |
| 941 Label alloc_failure; | 983 Label alloc_failure; |
| 942 __ push(left_); | 984 __ push(left_); |
| 943 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); | 985 __ AllocateHeapNumber(dst_, left_, no_reg, &after_alloc_failure); |
| 944 __ pop(left_); | 986 __ pop(left_); |
| 945 } | 987 } |
| 946 | 988 |
| 947 __ bind(&do_op); | 989 __ bind(&do_op); |
| 948 switch (op_) { | 990 switch (op_) { |
| 949 case Token::ADD: __ addsd(xmm0, xmm1); break; | 991 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 950 case Token::SUB: __ subsd(xmm0, xmm1); break; | 992 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 951 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 993 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 952 case Token::DIV: __ divsd(xmm0, xmm1); break; | 994 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 953 default: UNREACHABLE(); | 995 default: UNREACHABLE(); |
| 954 } | 996 } |
| 955 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); | 997 __ movdbl(FieldOperand(dst_, HeapNumber::kValueOffset), xmm0); |
| 956 __ jmp(&done); | 998 __ jmp(&done); |
| 957 | 999 |
| 958 __ bind(&after_alloc_failure); | 1000 __ bind(&after_alloc_failure); |
| 959 __ pop(left_); | 1001 __ pop(left_); |
| 960 __ bind(&call_runtime); | 1002 __ bind(&call_runtime); |
| 961 } | 1003 } |
| 962 GenericBinaryOpStub stub(op_, mode_, NO_SMI_CODE_IN_STUB); | 1004 GenericBinaryOpStub stub(op_, |
| 1005 mode_, |
| 1006 NO_SMI_CODE_IN_STUB, |
| 1007 NumberInfo::Combine(left_info_, right_info_)); |
| 963 stub.GenerateCall(masm_, left_, right_); | 1008 stub.GenerateCall(masm_, left_, right_); |
| 964 if (!dst_.is(eax)) __ mov(dst_, eax); | 1009 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 965 __ bind(&done); | 1010 __ bind(&done); |
| 966 } | 1011 } |
| 967 | 1012 |
| 968 | 1013 |
| 1014 static NumberInfo CalculateNumberInfo(NumberInfo operands_type, |
| 1015 Token::Value op, |
| 1016 const Result& right, |
| 1017 const Result& left) { |
| 1018 // Set NumberInfo of result according to the operation performed. |
| 1019 // Rely on the fact that smis have a 31 bit payload on ia32. |
| 1020 ASSERT(kSmiValueSize == 31); |
| 1021 switch (op) { |
| 1022 case Token::COMMA: |
| 1023 return right.number_info(); |
| 1024 case Token::OR: |
| 1025 case Token::AND: |
| 1026 // Result type can be either of the two input types. |
| 1027 return operands_type; |
| 1028 case Token::BIT_AND: { |
| 1029 // Anding with positive Smis will give you a Smi. |
| 1030 if (right.is_constant() && right.handle()->IsSmi() && |
| 1031 Smi::cast(*right.handle())->value() >= 0) { |
| 1032 return NumberInfo::Smi(); |
| 1033 } else if (left.is_constant() && left.handle()->IsSmi() && |
| 1034 Smi::cast(*left.handle())->value() >= 0) { |
| 1035 return NumberInfo::Smi(); |
| 1036 } |
| 1037 return (operands_type.IsSmi()) |
| 1038 ? NumberInfo::Smi() |
| 1039 : NumberInfo::Integer32(); |
| 1040 } |
| 1041 case Token::BIT_OR: { |
| 1042 // Oring with negative Smis will give you a Smi. |
| 1043 if (right.is_constant() && right.handle()->IsSmi() && |
| 1044 Smi::cast(*right.handle())->value() < 0) { |
| 1045 return NumberInfo::Smi(); |
| 1046 } else if (left.is_constant() && left.handle()->IsSmi() && |
| 1047 Smi::cast(*left.handle())->value() < 0) { |
| 1048 return NumberInfo::Smi(); |
| 1049 } |
| 1050 return (operands_type.IsSmi()) |
| 1051 ? NumberInfo::Smi() |
| 1052 : NumberInfo::Integer32(); |
| 1053 } |
| 1054 case Token::BIT_XOR: |
| 1055 // Result is always a 32 bit integer. Smi property of inputs is preserved. |
| 1056 return (operands_type.IsSmi()) |
| 1057 ? NumberInfo::Smi() |
| 1058 : NumberInfo::Integer32(); |
| 1059 case Token::SAR: |
| 1060 if (left.is_smi()) return NumberInfo::Smi(); |
| 1061 // Result is a smi if we shift by a constant >= 1, otherwise an integer32. |
| 1062 return (right.is_constant() && right.handle()->IsSmi() |
| 1063 && Smi::cast(*right.handle())->value() >= 1) |
| 1064 ? NumberInfo::Smi() |
| 1065 : NumberInfo::Integer32(); |
| 1066 case Token::SHR: |
| 1067 // Result is a smi if we shift by a constant >= 2, otherwise an integer32. |
| 1068 return (right.is_constant() && right.handle()->IsSmi() |
| 1069 && Smi::cast(*right.handle())->value() >= 2) |
| 1070 ? NumberInfo::Smi() |
| 1071 : NumberInfo::Integer32(); |
| 1072 case Token::ADD: |
| 1073 if (operands_type.IsSmi()) { |
| 1074 // The Integer32 range is big enough to take the sum of any two Smis. |
| 1075 return NumberInfo::Integer32(); |
| 1076 } else { |
| 1077 // Result could be a string or a number. Check types of inputs. |
| 1078 return operands_type.IsNumber() |
| 1079 ? NumberInfo::Number() |
| 1080 : NumberInfo::Unknown(); |
| 1081 } |
| 1082 case Token::SHL: |
| 1083 return NumberInfo::Integer32(); |
| 1084 case Token::SUB: |
| 1085 // The Integer32 range is big enough to take the difference of any two |
| 1086 // Smis. |
| 1087 return (operands_type.IsSmi()) ? |
| 1088 NumberInfo::Integer32() : |
| 1089 NumberInfo::Number(); |
| 1090 case Token::MUL: |
| 1091 case Token::DIV: |
| 1092 case Token::MOD: |
| 1093 // Result is always a number. |
| 1094 return NumberInfo::Number(); |
| 1095 default: |
| 1096 UNREACHABLE(); |
| 1097 } |
| 1098 UNREACHABLE(); |
| 1099 return NumberInfo::Unknown(); |
| 1100 } |
| 1101 |
| 1102 |
| 969 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 1103 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
| 970 StaticType* type, | 1104 StaticType* type, |
| 971 OverwriteMode overwrite_mode) { | 1105 OverwriteMode overwrite_mode) { |
| 972 Comment cmnt(masm_, "[ BinaryOperation"); | 1106 Comment cmnt(masm_, "[ BinaryOperation"); |
| 973 Comment cmnt_token(masm_, Token::String(op)); | 1107 Comment cmnt_token(masm_, Token::String(op)); |
| 974 | 1108 |
| 975 if (op == Token::COMMA) { | 1109 if (op == Token::COMMA) { |
| 976 // Simply discard left value. | 1110 // Simply discard left value. |
| 977 frame_->Nip(1); | 1111 frame_->Nip(1); |
| 978 return; | 1112 return; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1014 right.is_constant() && !right.handle()->IsSmi(); | 1148 right.is_constant() && !right.handle()->IsSmi(); |
| 1015 | 1149 |
| 1016 if (left_is_smi_constant && right_is_smi_constant) { | 1150 if (left_is_smi_constant && right_is_smi_constant) { |
| 1017 // Compute the constant result at compile time, and leave it on the frame. | 1151 // Compute the constant result at compile time, and leave it on the frame. |
| 1018 int left_int = Smi::cast(*left.handle())->value(); | 1152 int left_int = Smi::cast(*left.handle())->value(); |
| 1019 int right_int = Smi::cast(*right.handle())->value(); | 1153 int right_int = Smi::cast(*right.handle())->value(); |
| 1020 if (FoldConstantSmis(op, left_int, right_int)) return; | 1154 if (FoldConstantSmis(op, left_int, right_int)) return; |
| 1021 } | 1155 } |
| 1022 | 1156 |
| 1023 // Get number type of left and right sub-expressions. | 1157 // Get number type of left and right sub-expressions. |
| 1024 NumberInfo::Type operands_type = | 1158 NumberInfo operands_type = |
| 1025 NumberInfo::Combine(left.number_info(), right.number_info()); | 1159 NumberInfo::Combine(left.number_info(), right.number_info()); |
| 1026 | 1160 |
| 1161 NumberInfo result_type = CalculateNumberInfo(operands_type, op, right, left); |
| 1162 |
| 1027 Result answer; | 1163 Result answer; |
| 1028 if (left_is_non_smi_constant || right_is_non_smi_constant) { | 1164 if (left_is_non_smi_constant || right_is_non_smi_constant) { |
| 1029 // Go straight to the slow case, with no smi code. | 1165 // Go straight to the slow case, with no smi code. |
| 1030 GenericBinaryOpStub stub(op, | 1166 GenericBinaryOpStub stub(op, |
| 1031 overwrite_mode, | 1167 overwrite_mode, |
| 1032 NO_SMI_CODE_IN_STUB, | 1168 NO_SMI_CODE_IN_STUB, |
| 1033 operands_type); | 1169 operands_type); |
| 1034 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1170 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 1035 } else if (right_is_smi_constant) { | 1171 } else if (right_is_smi_constant) { |
| 1036 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), | 1172 answer = ConstantSmiBinaryOperation(op, &left, right.handle(), |
| 1037 type, false, overwrite_mode); | 1173 type, false, overwrite_mode); |
| 1038 } else if (left_is_smi_constant) { | 1174 } else if (left_is_smi_constant) { |
| 1039 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), | 1175 answer = ConstantSmiBinaryOperation(op, &right, left.handle(), |
| 1040 type, true, overwrite_mode); | 1176 type, true, overwrite_mode); |
| 1041 } else { | 1177 } else { |
| 1042 // Set the flags based on the operation, type and loop nesting level. | 1178 // Set the flags based on the operation, type and loop nesting level. |
| 1043 // Bit operations always assume they likely operate on Smis. Still only | 1179 // Bit operations always assume they likely operate on Smis. Still only |
| 1044 // generate the inline Smi check code if this operation is part of a loop. | 1180 // generate the inline Smi check code if this operation is part of a loop. |
| 1045 // For all other operations only inline the Smi check code for likely smis | 1181 // For all other operations only inline the Smi check code for likely smis |
| 1046 // if the operation is part of a loop. | 1182 // if the operation is part of a loop. |
| 1047 if (loop_nesting() > 0 && (Token::IsBitOp(op) || type->IsLikelySmi())) { | 1183 if (loop_nesting() > 0 && |
| 1184 (Token::IsBitOp(op) || |
| 1185 operands_type.IsInteger32() || |
| 1186 type->IsLikelySmi())) { |
| 1048 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); | 1187 answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode); |
| 1049 } else { | 1188 } else { |
| 1050 GenericBinaryOpStub stub(op, | 1189 GenericBinaryOpStub stub(op, |
| 1051 overwrite_mode, | 1190 overwrite_mode, |
| 1052 NO_GENERIC_BINARY_FLAGS, | 1191 NO_GENERIC_BINARY_FLAGS, |
| 1053 operands_type); | 1192 operands_type); |
| 1054 answer = stub.GenerateCall(masm_, frame_, &left, &right); | 1193 answer = stub.GenerateCall(masm_, frame_, &left, &right); |
| 1055 } | 1194 } |
| 1056 } | 1195 } |
| 1057 | 1196 |
| 1058 // Set NumberInfo of result according to the operation performed. | |
| 1059 // Rely on the fact that smis have a 31 bit payload on ia32. | |
| 1060 ASSERT(kSmiValueSize == 31); | |
| 1061 NumberInfo::Type result_type = NumberInfo::kUnknown; | |
| 1062 switch (op) { | |
| 1063 case Token::COMMA: | |
| 1064 result_type = right.number_info(); | |
| 1065 break; | |
| 1066 case Token::OR: | |
| 1067 case Token::AND: | |
| 1068 // Result type can be either of the two input types. | |
| 1069 result_type = operands_type; | |
| 1070 break; | |
| 1071 case Token::BIT_OR: | |
| 1072 case Token::BIT_XOR: | |
| 1073 case Token::BIT_AND: | |
| 1074 // Result is always a number. Smi property of inputs is preserved. | |
| 1075 result_type = (operands_type == NumberInfo::kSmi) | |
| 1076 ? NumberInfo::kSmi | |
| 1077 : NumberInfo::kNumber; | |
| 1078 break; | |
| 1079 case Token::SAR: | |
| 1080 // Result is a smi if we shift by a constant >= 1, otherwise a number. | |
| 1081 result_type = (right.is_constant() && right.handle()->IsSmi() | |
| 1082 && Smi::cast(*right.handle())->value() >= 1) | |
| 1083 ? NumberInfo::kSmi | |
| 1084 : NumberInfo::kNumber; | |
| 1085 break; | |
| 1086 case Token::SHR: | |
| 1087 // Result is a smi if we shift by a constant >= 2, otherwise a number. | |
| 1088 result_type = (right.is_constant() && right.handle()->IsSmi() | |
| 1089 && Smi::cast(*right.handle())->value() >= 2) | |
| 1090 ? NumberInfo::kSmi | |
| 1091 : NumberInfo::kNumber; | |
| 1092 break; | |
| 1093 case Token::ADD: | |
| 1094 // Result could be a string or a number. Check types of inputs. | |
| 1095 result_type = NumberInfo::IsNumber(operands_type) | |
| 1096 ? NumberInfo::kNumber | |
| 1097 : NumberInfo::kUnknown; | |
| 1098 break; | |
| 1099 case Token::SHL: | |
| 1100 case Token::SUB: | |
| 1101 case Token::MUL: | |
| 1102 case Token::DIV: | |
| 1103 case Token::MOD: | |
| 1104 // Result is always a number. | |
| 1105 result_type = NumberInfo::kNumber; | |
| 1106 break; | |
| 1107 default: | |
| 1108 UNREACHABLE(); | |
| 1109 } | |
| 1110 answer.set_number_info(result_type); | 1197 answer.set_number_info(result_type); |
| 1111 frame_->Push(&answer); | 1198 frame_->Push(&answer); |
| 1112 } | 1199 } |
| 1113 | 1200 |
| 1114 | 1201 |
| 1115 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 1202 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
| 1116 Object* answer_object = Heap::undefined_value(); | 1203 Object* answer_object = Heap::undefined_value(); |
| 1117 switch (op) { | 1204 switch (op) { |
| 1118 case Token::ADD: | 1205 case Token::ADD: |
| 1119 if (Smi::IsValid(left + right)) { | 1206 if (Smi::IsValid(left + right)) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1186 break; | 1273 break; |
| 1187 } | 1274 } |
| 1188 if (answer_object == Heap::undefined_value()) { | 1275 if (answer_object == Heap::undefined_value()) { |
| 1189 return false; | 1276 return false; |
| 1190 } | 1277 } |
| 1191 frame_->Push(Handle<Object>(answer_object)); | 1278 frame_->Push(Handle<Object>(answer_object)); |
| 1192 return true; | 1279 return true; |
| 1193 } | 1280 } |
| 1194 | 1281 |
| 1195 | 1282 |
| 1283 static void CheckTwoForSminess(MacroAssembler* masm, |
| 1284 Register left, Register right, Register scratch, |
| 1285 NumberInfo left_info, NumberInfo right_info, |
| 1286 DeferredInlineBinaryOperation* deferred); |
| 1287 |
| 1288 |
| 1196 // Implements a binary operation using a deferred code object and some | 1289 // Implements a binary operation using a deferred code object and some |
| 1197 // inline code to operate on smis quickly. | 1290 // inline code to operate on smis quickly. |
| 1198 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, | 1291 Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op, |
| 1199 Result* left, | 1292 Result* left, |
| 1200 Result* right, | 1293 Result* right, |
| 1201 OverwriteMode overwrite_mode) { | 1294 OverwriteMode overwrite_mode) { |
| 1202 Result answer; | 1295 Result answer; |
| 1203 // Special handling of div and mod because they use fixed registers. | 1296 // Special handling of div and mod because they use fixed registers. |
| 1204 if (op == Token::DIV || op == Token::MOD) { | 1297 if (op == Token::DIV || op == Token::MOD) { |
| 1205 // We need eax as the quotient register, edx as the remainder | 1298 // We need eax as the quotient register, edx as the remainder |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 right->ToRegister(); | 1359 right->ToRegister(); |
| 1267 frame_->Spill(eax); | 1360 frame_->Spill(eax); |
| 1268 frame_->Spill(edx); | 1361 frame_->Spill(edx); |
| 1269 | 1362 |
| 1270 // Check that left and right are smi tagged. | 1363 // Check that left and right are smi tagged. |
| 1271 DeferredInlineBinaryOperation* deferred = | 1364 DeferredInlineBinaryOperation* deferred = |
| 1272 new DeferredInlineBinaryOperation(op, | 1365 new DeferredInlineBinaryOperation(op, |
| 1273 (op == Token::DIV) ? eax : edx, | 1366 (op == Token::DIV) ? eax : edx, |
| 1274 left->reg(), | 1367 left->reg(), |
| 1275 right->reg(), | 1368 right->reg(), |
| 1369 left->number_info(), |
| 1370 right->number_info(), |
| 1276 overwrite_mode); | 1371 overwrite_mode); |
| 1277 if (left->reg().is(right->reg())) { | 1372 if (left->reg().is(right->reg())) { |
| 1278 __ test(left->reg(), Immediate(kSmiTagMask)); | 1373 __ test(left->reg(), Immediate(kSmiTagMask)); |
| 1279 } else { | 1374 } else { |
| 1280 // Use the quotient register as a scratch for the tag check. | 1375 // Use the quotient register as a scratch for the tag check. |
| 1281 if (!left_is_in_eax) __ mov(eax, left->reg()); | 1376 if (!left_is_in_eax) __ mov(eax, left->reg()); |
| 1282 left_is_in_eax = false; // About to destroy the value in eax. | 1377 left_is_in_eax = false; // About to destroy the value in eax. |
| 1283 __ or_(eax, Operand(right->reg())); | 1378 __ or_(eax, Operand(right->reg())); |
| 1284 ASSERT(kSmiTag == 0); // Adjust test if not the case. | 1379 ASSERT(kSmiTag == 0); // Adjust test if not the case. |
| 1285 __ test(eax, Immediate(kSmiTagMask)); | 1380 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1363 // Use a fresh answer register to avoid spilling the left operand. | 1458 // Use a fresh answer register to avoid spilling the left operand. |
| 1364 answer = allocator_->Allocate(); | 1459 answer = allocator_->Allocate(); |
| 1365 ASSERT(answer.is_valid()); | 1460 ASSERT(answer.is_valid()); |
| 1366 // Check that both operands are smis using the answer register as a | 1461 // Check that both operands are smis using the answer register as a |
| 1367 // temporary. | 1462 // temporary. |
| 1368 DeferredInlineBinaryOperation* deferred = | 1463 DeferredInlineBinaryOperation* deferred = |
| 1369 new DeferredInlineBinaryOperation(op, | 1464 new DeferredInlineBinaryOperation(op, |
| 1370 answer.reg(), | 1465 answer.reg(), |
| 1371 left->reg(), | 1466 left->reg(), |
| 1372 ecx, | 1467 ecx, |
| 1468 left->number_info(), |
| 1469 right->number_info(), |
| 1373 overwrite_mode); | 1470 overwrite_mode); |
| 1374 __ mov(answer.reg(), left->reg()); | 1471 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
| 1375 __ or_(answer.reg(), Operand(ecx)); | 1472 left->number_info(), right->number_info(), deferred); |
| 1376 __ test(answer.reg(), Immediate(kSmiTagMask)); | |
| 1377 deferred->Branch(not_zero); | |
| 1378 | 1473 |
| 1379 // Untag both operands. | 1474 // Untag both operands. |
| 1380 __ mov(answer.reg(), left->reg()); | 1475 __ mov(answer.reg(), left->reg()); |
| 1381 __ SmiUntag(answer.reg()); | 1476 __ SmiUntag(answer.reg()); |
| 1382 __ SmiUntag(ecx); | 1477 __ SmiUntag(ecx); |
| 1383 // Perform the operation. | 1478 // Perform the operation. |
| 1384 switch (op) { | 1479 switch (op) { |
| 1385 case Token::SAR: | 1480 case Token::SAR: |
| 1386 __ sar_cl(answer.reg()); | 1481 __ sar_cl(answer.reg()); |
| 1387 // No checks of result necessary | 1482 // No checks of result necessary |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1437 // need to be spilled in the fast case. | 1532 // need to be spilled in the fast case. |
| 1438 answer = allocator_->Allocate(); | 1533 answer = allocator_->Allocate(); |
| 1439 ASSERT(answer.is_valid()); | 1534 ASSERT(answer.is_valid()); |
| 1440 | 1535 |
| 1441 // Perform the smi tag check. | 1536 // Perform the smi tag check. |
| 1442 DeferredInlineBinaryOperation* deferred = | 1537 DeferredInlineBinaryOperation* deferred = |
| 1443 new DeferredInlineBinaryOperation(op, | 1538 new DeferredInlineBinaryOperation(op, |
| 1444 answer.reg(), | 1539 answer.reg(), |
| 1445 left->reg(), | 1540 left->reg(), |
| 1446 right->reg(), | 1541 right->reg(), |
| 1542 left->number_info(), |
| 1543 right->number_info(), |
| 1447 overwrite_mode); | 1544 overwrite_mode); |
| 1448 if (left->reg().is(right->reg())) { | 1545 CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(), |
| 1449 __ test(left->reg(), Immediate(kSmiTagMask)); | 1546 left->number_info(), right->number_info(), deferred); |
| 1450 } else { | 1547 |
| 1451 __ mov(answer.reg(), left->reg()); | |
| 1452 __ or_(answer.reg(), Operand(right->reg())); | |
| 1453 ASSERT(kSmiTag == 0); // Adjust test if not the case. | |
| 1454 __ test(answer.reg(), Immediate(kSmiTagMask)); | |
| 1455 } | |
| 1456 deferred->Branch(not_zero); | |
| 1457 __ mov(answer.reg(), left->reg()); | 1548 __ mov(answer.reg(), left->reg()); |
| 1458 switch (op) { | 1549 switch (op) { |
| 1459 case Token::ADD: | 1550 case Token::ADD: |
| 1460 __ add(answer.reg(), Operand(right->reg())); | 1551 __ add(answer.reg(), Operand(right->reg())); |
| 1461 deferred->Branch(overflow); | 1552 deferred->Branch(overflow); |
| 1462 break; | 1553 break; |
| 1463 | 1554 |
| 1464 case Token::SUB: | 1555 case Token::SUB: |
| 1465 __ sub(answer.reg(), Operand(right->reg())); | 1556 __ sub(answer.reg(), Operand(right->reg())); |
| 1466 deferred->Branch(overflow); | 1557 deferred->Branch(overflow); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1515 } | 1606 } |
| 1516 | 1607 |
| 1517 | 1608 |
| 1518 // Call the appropriate binary operation stub to compute src op value | 1609 // Call the appropriate binary operation stub to compute src op value |
| 1519 // and leave the result in dst. | 1610 // and leave the result in dst. |
| 1520 class DeferredInlineSmiOperation: public DeferredCode { | 1611 class DeferredInlineSmiOperation: public DeferredCode { |
| 1521 public: | 1612 public: |
| 1522 DeferredInlineSmiOperation(Token::Value op, | 1613 DeferredInlineSmiOperation(Token::Value op, |
| 1523 Register dst, | 1614 Register dst, |
| 1524 Register src, | 1615 Register src, |
| 1616 NumberInfo number_info, |
| 1525 Smi* value, | 1617 Smi* value, |
| 1526 OverwriteMode overwrite_mode) | 1618 OverwriteMode overwrite_mode) |
| 1527 : op_(op), | 1619 : op_(op), |
| 1528 dst_(dst), | 1620 dst_(dst), |
| 1529 src_(src), | 1621 src_(src), |
| 1622 number_info_(number_info), |
| 1530 value_(value), | 1623 value_(value), |
| 1531 overwrite_mode_(overwrite_mode) { | 1624 overwrite_mode_(overwrite_mode) { |
| 1625 if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; |
| 1532 set_comment("[ DeferredInlineSmiOperation"); | 1626 set_comment("[ DeferredInlineSmiOperation"); |
| 1533 } | 1627 } |
| 1534 | 1628 |
| 1535 virtual void Generate(); | 1629 virtual void Generate(); |
| 1536 | 1630 |
| 1537 private: | 1631 private: |
| 1538 Token::Value op_; | 1632 Token::Value op_; |
| 1539 Register dst_; | 1633 Register dst_; |
| 1540 Register src_; | 1634 Register src_; |
| 1635 NumberInfo number_info_; |
| 1541 Smi* value_; | 1636 Smi* value_; |
| 1542 OverwriteMode overwrite_mode_; | 1637 OverwriteMode overwrite_mode_; |
| 1543 }; | 1638 }; |
| 1544 | 1639 |
| 1545 | 1640 |
| 1546 void DeferredInlineSmiOperation::Generate() { | 1641 void DeferredInlineSmiOperation::Generate() { |
| 1547 // For mod we don't generate all the Smi code inline. | 1642 // For mod we don't generate all the Smi code inline. |
| 1548 GenericBinaryOpStub stub( | 1643 GenericBinaryOpStub stub( |
| 1549 op_, | 1644 op_, |
| 1550 overwrite_mode_, | 1645 overwrite_mode_, |
| 1551 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB); | 1646 (op_ == Token::MOD) ? NO_GENERIC_BINARY_FLAGS : NO_SMI_CODE_IN_STUB, |
| 1647 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); |
| 1552 stub.GenerateCall(masm_, src_, value_); | 1648 stub.GenerateCall(masm_, src_, value_); |
| 1553 if (!dst_.is(eax)) __ mov(dst_, eax); | 1649 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1554 } | 1650 } |
| 1555 | 1651 |
| 1556 | 1652 |
| 1557 // Call the appropriate binary operation stub to compute value op src | 1653 // Call the appropriate binary operation stub to compute value op src |
| 1558 // and leave the result in dst. | 1654 // and leave the result in dst. |
| 1559 class DeferredInlineSmiOperationReversed: public DeferredCode { | 1655 class DeferredInlineSmiOperationReversed: public DeferredCode { |
| 1560 public: | 1656 public: |
| 1561 DeferredInlineSmiOperationReversed(Token::Value op, | 1657 DeferredInlineSmiOperationReversed(Token::Value op, |
| 1562 Register dst, | 1658 Register dst, |
| 1563 Smi* value, | 1659 Smi* value, |
| 1564 Register src, | 1660 Register src, |
| 1661 NumberInfo number_info, |
| 1565 OverwriteMode overwrite_mode) | 1662 OverwriteMode overwrite_mode) |
| 1566 : op_(op), | 1663 : op_(op), |
| 1567 dst_(dst), | 1664 dst_(dst), |
| 1665 number_info_(number_info), |
| 1568 value_(value), | 1666 value_(value), |
| 1569 src_(src), | 1667 src_(src), |
| 1570 overwrite_mode_(overwrite_mode) { | 1668 overwrite_mode_(overwrite_mode) { |
| 1571 set_comment("[ DeferredInlineSmiOperationReversed"); | 1669 set_comment("[ DeferredInlineSmiOperationReversed"); |
| 1572 } | 1670 } |
| 1573 | 1671 |
| 1574 virtual void Generate(); | 1672 virtual void Generate(); |
| 1575 | 1673 |
| 1576 private: | 1674 private: |
| 1577 Token::Value op_; | 1675 Token::Value op_; |
| 1578 Register dst_; | 1676 Register dst_; |
| 1677 NumberInfo number_info_; |
| 1579 Smi* value_; | 1678 Smi* value_; |
| 1580 Register src_; | 1679 Register src_; |
| 1581 OverwriteMode overwrite_mode_; | 1680 OverwriteMode overwrite_mode_; |
| 1582 }; | 1681 }; |
| 1583 | 1682 |
| 1584 | 1683 |
| 1585 void DeferredInlineSmiOperationReversed::Generate() { | 1684 void DeferredInlineSmiOperationReversed::Generate() { |
| 1586 GenericBinaryOpStub igostub(op_, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1685 GenericBinaryOpStub igostub( |
| 1686 op_, |
| 1687 overwrite_mode_, |
| 1688 NO_SMI_CODE_IN_STUB, |
| 1689 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); |
| 1587 igostub.GenerateCall(masm_, value_, src_); | 1690 igostub.GenerateCall(masm_, value_, src_); |
| 1588 if (!dst_.is(eax)) __ mov(dst_, eax); | 1691 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1589 } | 1692 } |
| 1590 | 1693 |
| 1591 | 1694 |
| 1592 // The result of src + value is in dst. It either overflowed or was not | 1695 // The result of src + value is in dst. It either overflowed or was not |
| 1593 // smi tagged. Undo the speculative addition and call the appropriate | 1696 // smi tagged. Undo the speculative addition and call the appropriate |
| 1594 // specialized stub for add. The result is left in dst. | 1697 // specialized stub for add. The result is left in dst. |
| 1595 class DeferredInlineSmiAdd: public DeferredCode { | 1698 class DeferredInlineSmiAdd: public DeferredCode { |
| 1596 public: | 1699 public: |
| 1597 DeferredInlineSmiAdd(Register dst, | 1700 DeferredInlineSmiAdd(Register dst, |
| 1701 NumberInfo number_info, |
| 1598 Smi* value, | 1702 Smi* value, |
| 1599 OverwriteMode overwrite_mode) | 1703 OverwriteMode overwrite_mode) |
| 1600 : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 1704 : dst_(dst), |
| 1705 number_info_(number_info), |
| 1706 value_(value), |
| 1707 overwrite_mode_(overwrite_mode) { |
| 1708 if (number_info_.IsSmi()) overwrite_mode_ = NO_OVERWRITE; |
| 1601 set_comment("[ DeferredInlineSmiAdd"); | 1709 set_comment("[ DeferredInlineSmiAdd"); |
| 1602 } | 1710 } |
| 1603 | 1711 |
| 1604 virtual void Generate(); | 1712 virtual void Generate(); |
| 1605 | 1713 |
| 1606 private: | 1714 private: |
| 1607 Register dst_; | 1715 Register dst_; |
| 1716 NumberInfo number_info_; |
| 1608 Smi* value_; | 1717 Smi* value_; |
| 1609 OverwriteMode overwrite_mode_; | 1718 OverwriteMode overwrite_mode_; |
| 1610 }; | 1719 }; |
| 1611 | 1720 |
| 1612 | 1721 |
| 1613 void DeferredInlineSmiAdd::Generate() { | 1722 void DeferredInlineSmiAdd::Generate() { |
| 1614 // Undo the optimistic add operation and call the shared stub. | 1723 // Undo the optimistic add operation and call the shared stub. |
| 1615 __ sub(Operand(dst_), Immediate(value_)); | 1724 __ sub(Operand(dst_), Immediate(value_)); |
| 1616 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1725 GenericBinaryOpStub igostub( |
| 1726 Token::ADD, |
| 1727 overwrite_mode_, |
| 1728 NO_SMI_CODE_IN_STUB, |
| 1729 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); |
| 1617 igostub.GenerateCall(masm_, dst_, value_); | 1730 igostub.GenerateCall(masm_, dst_, value_); |
| 1618 if (!dst_.is(eax)) __ mov(dst_, eax); | 1731 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1619 } | 1732 } |
| 1620 | 1733 |
| 1621 | 1734 |
| 1622 // The result of value + src is in dst. It either overflowed or was not | 1735 // The result of value + src is in dst. It either overflowed or was not |
| 1623 // smi tagged. Undo the speculative addition and call the appropriate | 1736 // smi tagged. Undo the speculative addition and call the appropriate |
| 1624 // specialized stub for add. The result is left in dst. | 1737 // specialized stub for add. The result is left in dst. |
| 1625 class DeferredInlineSmiAddReversed: public DeferredCode { | 1738 class DeferredInlineSmiAddReversed: public DeferredCode { |
| 1626 public: | 1739 public: |
| 1627 DeferredInlineSmiAddReversed(Register dst, | 1740 DeferredInlineSmiAddReversed(Register dst, |
| 1741 NumberInfo number_info, |
| 1628 Smi* value, | 1742 Smi* value, |
| 1629 OverwriteMode overwrite_mode) | 1743 OverwriteMode overwrite_mode) |
| 1630 : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 1744 : dst_(dst), |
| 1745 number_info_(number_info), |
| 1746 value_(value), |
| 1747 overwrite_mode_(overwrite_mode) { |
| 1631 set_comment("[ DeferredInlineSmiAddReversed"); | 1748 set_comment("[ DeferredInlineSmiAddReversed"); |
| 1632 } | 1749 } |
| 1633 | 1750 |
| 1634 virtual void Generate(); | 1751 virtual void Generate(); |
| 1635 | 1752 |
| 1636 private: | 1753 private: |
| 1637 Register dst_; | 1754 Register dst_; |
| 1755 NumberInfo number_info_; |
| 1638 Smi* value_; | 1756 Smi* value_; |
| 1639 OverwriteMode overwrite_mode_; | 1757 OverwriteMode overwrite_mode_; |
| 1640 }; | 1758 }; |
| 1641 | 1759 |
| 1642 | 1760 |
| 1643 void DeferredInlineSmiAddReversed::Generate() { | 1761 void DeferredInlineSmiAddReversed::Generate() { |
| 1644 // Undo the optimistic add operation and call the shared stub. | 1762 // Undo the optimistic add operation and call the shared stub. |
| 1645 __ sub(Operand(dst_), Immediate(value_)); | 1763 __ sub(Operand(dst_), Immediate(value_)); |
| 1646 GenericBinaryOpStub igostub(Token::ADD, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1764 GenericBinaryOpStub igostub( |
| 1765 Token::ADD, |
| 1766 overwrite_mode_, |
| 1767 NO_SMI_CODE_IN_STUB, |
| 1768 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); |
| 1647 igostub.GenerateCall(masm_, value_, dst_); | 1769 igostub.GenerateCall(masm_, value_, dst_); |
| 1648 if (!dst_.is(eax)) __ mov(dst_, eax); | 1770 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1649 } | 1771 } |
| 1650 | 1772 |
| 1651 | 1773 |
| 1652 // The result of src - value is in dst. It either overflowed or was not | 1774 // The result of src - value is in dst. It either overflowed or was not |
| 1653 // smi tagged. Undo the speculative subtraction and call the | 1775 // smi tagged. Undo the speculative subtraction and call the |
| 1654 // appropriate specialized stub for subtract. The result is left in | 1776 // appropriate specialized stub for subtract. The result is left in |
| 1655 // dst. | 1777 // dst. |
| 1656 class DeferredInlineSmiSub: public DeferredCode { | 1778 class DeferredInlineSmiSub: public DeferredCode { |
| 1657 public: | 1779 public: |
| 1658 DeferredInlineSmiSub(Register dst, | 1780 DeferredInlineSmiSub(Register dst, |
| 1781 NumberInfo number_info, |
| 1659 Smi* value, | 1782 Smi* value, |
| 1660 OverwriteMode overwrite_mode) | 1783 OverwriteMode overwrite_mode) |
| 1661 : dst_(dst), value_(value), overwrite_mode_(overwrite_mode) { | 1784 : dst_(dst), |
| 1785 number_info_(number_info), |
| 1786 value_(value), |
| 1787 overwrite_mode_(overwrite_mode) { |
| 1788 if (number_info.IsSmi()) overwrite_mode_ = NO_OVERWRITE; |
| 1662 set_comment("[ DeferredInlineSmiSub"); | 1789 set_comment("[ DeferredInlineSmiSub"); |
| 1663 } | 1790 } |
| 1664 | 1791 |
| 1665 virtual void Generate(); | 1792 virtual void Generate(); |
| 1666 | 1793 |
| 1667 private: | 1794 private: |
| 1668 Register dst_; | 1795 Register dst_; |
| 1796 NumberInfo number_info_; |
| 1669 Smi* value_; | 1797 Smi* value_; |
| 1670 OverwriteMode overwrite_mode_; | 1798 OverwriteMode overwrite_mode_; |
| 1671 }; | 1799 }; |
| 1672 | 1800 |
| 1673 | 1801 |
| 1674 void DeferredInlineSmiSub::Generate() { | 1802 void DeferredInlineSmiSub::Generate() { |
| 1675 // Undo the optimistic sub operation and call the shared stub. | 1803 // Undo the optimistic sub operation and call the shared stub. |
| 1676 __ add(Operand(dst_), Immediate(value_)); | 1804 __ add(Operand(dst_), Immediate(value_)); |
| 1677 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1805 GenericBinaryOpStub igostub( |
| 1806 Token::SUB, |
| 1807 overwrite_mode_, |
| 1808 NO_SMI_CODE_IN_STUB, |
| 1809 NumberInfo::Combine(NumberInfo::Smi(), number_info_)); |
| 1678 igostub.GenerateCall(masm_, dst_, value_); | 1810 igostub.GenerateCall(masm_, dst_, value_); |
| 1679 if (!dst_.is(eax)) __ mov(dst_, eax); | 1811 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 1680 } | 1812 } |
| 1681 | 1813 |
| 1682 | 1814 |
| 1683 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, | 1815 Result CodeGenerator::ConstantSmiBinaryOperation(Token::Value op, |
| 1684 Result* operand, | 1816 Result* operand, |
| 1685 Handle<Object> value, | 1817 Handle<Object> value, |
| 1686 StaticType* type, | 1818 StaticType* type, |
| 1687 bool reversed, | 1819 bool reversed, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1711 switch (op) { | 1843 switch (op) { |
| 1712 case Token::ADD: { | 1844 case Token::ADD: { |
| 1713 operand->ToRegister(); | 1845 operand->ToRegister(); |
| 1714 frame_->Spill(operand->reg()); | 1846 frame_->Spill(operand->reg()); |
| 1715 | 1847 |
| 1716 // Optimistically add. Call the specialized add stub if the | 1848 // Optimistically add. Call the specialized add stub if the |
| 1717 // result is not a smi or overflows. | 1849 // result is not a smi or overflows. |
| 1718 DeferredCode* deferred = NULL; | 1850 DeferredCode* deferred = NULL; |
| 1719 if (reversed) { | 1851 if (reversed) { |
| 1720 deferred = new DeferredInlineSmiAddReversed(operand->reg(), | 1852 deferred = new DeferredInlineSmiAddReversed(operand->reg(), |
| 1853 operand->number_info(), |
| 1721 smi_value, | 1854 smi_value, |
| 1722 overwrite_mode); | 1855 overwrite_mode); |
| 1723 } else { | 1856 } else { |
| 1724 deferred = new DeferredInlineSmiAdd(operand->reg(), | 1857 deferred = new DeferredInlineSmiAdd(operand->reg(), |
| 1858 operand->number_info(), |
| 1725 smi_value, | 1859 smi_value, |
| 1726 overwrite_mode); | 1860 overwrite_mode); |
| 1727 } | 1861 } |
| 1728 __ add(Operand(operand->reg()), Immediate(value)); | 1862 __ add(Operand(operand->reg()), Immediate(value)); |
| 1729 deferred->Branch(overflow); | 1863 deferred->Branch(overflow); |
| 1730 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1864 if (!operand->number_info().IsSmi()) { |
| 1731 deferred->Branch(not_zero); | 1865 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1866 deferred->Branch(not_zero); |
| 1867 } |
| 1732 deferred->BindExit(); | 1868 deferred->BindExit(); |
| 1733 answer = *operand; | 1869 answer = *operand; |
| 1734 break; | 1870 break; |
| 1735 } | 1871 } |
| 1736 | 1872 |
| 1737 case Token::SUB: { | 1873 case Token::SUB: { |
| 1738 DeferredCode* deferred = NULL; | 1874 DeferredCode* deferred = NULL; |
| 1739 if (reversed) { | 1875 if (reversed) { |
| 1740 // The reversed case is only hit when the right operand is not a | 1876 // The reversed case is only hit when the right operand is not a |
| 1741 // constant. | 1877 // constant. |
| 1742 ASSERT(operand->is_register()); | 1878 ASSERT(operand->is_register()); |
| 1743 answer = allocator()->Allocate(); | 1879 answer = allocator()->Allocate(); |
| 1744 ASSERT(answer.is_valid()); | 1880 ASSERT(answer.is_valid()); |
| 1745 __ Set(answer.reg(), Immediate(value)); | 1881 __ Set(answer.reg(), Immediate(value)); |
| 1746 deferred = new DeferredInlineSmiOperationReversed(op, | 1882 deferred = |
| 1747 answer.reg(), | 1883 new DeferredInlineSmiOperationReversed(op, |
| 1748 smi_value, | 1884 answer.reg(), |
| 1749 operand->reg(), | 1885 smi_value, |
| 1750 overwrite_mode); | 1886 operand->reg(), |
| 1887 operand->number_info(), |
| 1888 overwrite_mode); |
| 1751 __ sub(answer.reg(), Operand(operand->reg())); | 1889 __ sub(answer.reg(), Operand(operand->reg())); |
| 1752 } else { | 1890 } else { |
| 1753 operand->ToRegister(); | 1891 operand->ToRegister(); |
| 1754 frame_->Spill(operand->reg()); | 1892 frame_->Spill(operand->reg()); |
| 1755 answer = *operand; | 1893 answer = *operand; |
| 1756 deferred = new DeferredInlineSmiSub(operand->reg(), | 1894 deferred = new DeferredInlineSmiSub(operand->reg(), |
| 1895 operand->number_info(), |
| 1757 smi_value, | 1896 smi_value, |
| 1758 overwrite_mode); | 1897 overwrite_mode); |
| 1759 __ sub(Operand(operand->reg()), Immediate(value)); | 1898 __ sub(Operand(operand->reg()), Immediate(value)); |
| 1760 } | 1899 } |
| 1761 deferred->Branch(overflow); | 1900 deferred->Branch(overflow); |
| 1762 __ test(answer.reg(), Immediate(kSmiTagMask)); | 1901 if (!operand->number_info().IsSmi()) { |
| 1763 deferred->Branch(not_zero); | 1902 __ test(answer.reg(), Immediate(kSmiTagMask)); |
| 1903 deferred->Branch(not_zero); |
| 1904 } |
| 1764 deferred->BindExit(); | 1905 deferred->BindExit(); |
| 1765 operand->Unuse(); | 1906 operand->Unuse(); |
| 1766 break; | 1907 break; |
| 1767 } | 1908 } |
| 1768 | 1909 |
| 1769 case Token::SAR: | 1910 case Token::SAR: |
| 1770 if (reversed) { | 1911 if (reversed) { |
| 1771 Result constant_operand(value); | 1912 Result constant_operand(value); |
| 1772 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 1913 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1773 overwrite_mode); | 1914 overwrite_mode); |
| 1774 } else { | 1915 } else { |
| 1775 // Only the least significant 5 bits of the shift value are used. | 1916 // Only the least significant 5 bits of the shift value are used. |
| 1776 // In the slow case, this masking is done inside the runtime call. | 1917 // In the slow case, this masking is done inside the runtime call. |
| 1777 int shift_value = int_value & 0x1f; | 1918 int shift_value = int_value & 0x1f; |
| 1778 operand->ToRegister(); | 1919 operand->ToRegister(); |
| 1779 frame_->Spill(operand->reg()); | 1920 frame_->Spill(operand->reg()); |
| 1780 DeferredInlineSmiOperation* deferred = | 1921 if (!operand->number_info().IsSmi()) { |
| 1781 new DeferredInlineSmiOperation(op, | 1922 DeferredInlineSmiOperation* deferred = |
| 1782 operand->reg(), | 1923 new DeferredInlineSmiOperation(op, |
| 1783 operand->reg(), | 1924 operand->reg(), |
| 1784 smi_value, | 1925 operand->reg(), |
| 1785 overwrite_mode); | 1926 operand->number_info(), |
| 1786 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1927 smi_value, |
| 1787 deferred->Branch(not_zero); | 1928 overwrite_mode); |
| 1788 if (shift_value > 0) { | 1929 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1789 __ sar(operand->reg(), shift_value); | 1930 deferred->Branch(not_zero); |
| 1790 __ and_(operand->reg(), ~kSmiTagMask); | 1931 if (shift_value > 0) { |
| 1932 __ sar(operand->reg(), shift_value); |
| 1933 __ and_(operand->reg(), ~kSmiTagMask); |
| 1934 } |
| 1935 deferred->BindExit(); |
| 1936 } else { |
| 1937 if (shift_value > 0) { |
| 1938 __ sar(operand->reg(), shift_value); |
| 1939 __ and_(operand->reg(), ~kSmiTagMask); |
| 1940 } |
| 1791 } | 1941 } |
| 1792 deferred->BindExit(); | |
| 1793 answer = *operand; | 1942 answer = *operand; |
| 1794 } | 1943 } |
| 1795 break; | 1944 break; |
| 1796 | 1945 |
| 1797 case Token::SHR: | 1946 case Token::SHR: |
| 1798 if (reversed) { | 1947 if (reversed) { |
| 1799 Result constant_operand(value); | 1948 Result constant_operand(value); |
| 1800 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, | 1949 answer = LikelySmiBinaryOperation(op, &constant_operand, operand, |
| 1801 overwrite_mode); | 1950 overwrite_mode); |
| 1802 } else { | 1951 } else { |
| 1803 // Only the least significant 5 bits of the shift value are used. | 1952 // Only the least significant 5 bits of the shift value are used. |
| 1804 // In the slow case, this masking is done inside the runtime call. | 1953 // In the slow case, this masking is done inside the runtime call. |
| 1805 int shift_value = int_value & 0x1f; | 1954 int shift_value = int_value & 0x1f; |
| 1806 operand->ToRegister(); | 1955 operand->ToRegister(); |
| 1807 answer = allocator()->Allocate(); | 1956 answer = allocator()->Allocate(); |
| 1808 ASSERT(answer.is_valid()); | 1957 ASSERT(answer.is_valid()); |
| 1809 DeferredInlineSmiOperation* deferred = | 1958 DeferredInlineSmiOperation* deferred = |
| 1810 new DeferredInlineSmiOperation(op, | 1959 new DeferredInlineSmiOperation(op, |
| 1811 answer.reg(), | 1960 answer.reg(), |
| 1812 operand->reg(), | 1961 operand->reg(), |
| 1962 operand->number_info(), |
| 1813 smi_value, | 1963 smi_value, |
| 1814 overwrite_mode); | 1964 overwrite_mode); |
| 1815 __ test(operand->reg(), Immediate(kSmiTagMask)); | 1965 if (!operand->number_info().IsSmi()) { |
| 1816 deferred->Branch(not_zero); | 1966 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1967 deferred->Branch(not_zero); |
| 1968 } |
| 1817 __ mov(answer.reg(), operand->reg()); | 1969 __ mov(answer.reg(), operand->reg()); |
| 1818 __ SmiUntag(answer.reg()); | 1970 __ SmiUntag(answer.reg()); |
| 1819 __ shr(answer.reg(), shift_value); | 1971 __ shr(answer.reg(), shift_value); |
| 1820 // A negative Smi shifted right two is in the positive Smi range. | 1972 // A negative Smi shifted right two is in the positive Smi range. |
| 1821 if (shift_value < 2) { | 1973 if (shift_value < 2) { |
| 1822 __ test(answer.reg(), Immediate(0xc0000000)); | 1974 __ test(answer.reg(), Immediate(0xc0000000)); |
| 1823 deferred->Branch(not_zero); | 1975 deferred->Branch(not_zero); |
| 1824 } | 1976 } |
| 1825 operand->Unuse(); | 1977 operand->Unuse(); |
| 1826 __ SmiTag(answer.reg()); | 1978 __ SmiTag(answer.reg()); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1848 right = *operand; | 2000 right = *operand; |
| 1849 } | 2001 } |
| 1850 operand->Unuse(); | 2002 operand->Unuse(); |
| 1851 | 2003 |
| 1852 answer = allocator()->Allocate(); | 2004 answer = allocator()->Allocate(); |
| 1853 DeferredInlineSmiOperationReversed* deferred = | 2005 DeferredInlineSmiOperationReversed* deferred = |
| 1854 new DeferredInlineSmiOperationReversed(op, | 2006 new DeferredInlineSmiOperationReversed(op, |
| 1855 answer.reg(), | 2007 answer.reg(), |
| 1856 smi_value, | 2008 smi_value, |
| 1857 right.reg(), | 2009 right.reg(), |
| 2010 right.number_info(), |
| 1858 overwrite_mode); | 2011 overwrite_mode); |
| 1859 __ mov(answer.reg(), Immediate(int_value)); | 2012 __ mov(answer.reg(), Immediate(int_value)); |
| 1860 __ sar(ecx, kSmiTagSize); | 2013 __ sar(ecx, kSmiTagSize); |
| 1861 deferred->Branch(carry); | 2014 if (!right.number_info().IsSmi()) { |
| 2015 deferred->Branch(carry); |
| 2016 } |
| 1862 __ shl_cl(answer.reg()); | 2017 __ shl_cl(answer.reg()); |
| 1863 __ cmp(answer.reg(), 0xc0000000); | 2018 __ cmp(answer.reg(), 0xc0000000); |
| 1864 deferred->Branch(sign); | 2019 deferred->Branch(sign); |
| 1865 __ SmiTag(answer.reg()); | 2020 __ SmiTag(answer.reg()); |
| 1866 | 2021 |
| 1867 deferred->BindExit(); | 2022 deferred->BindExit(); |
| 1868 } else { | 2023 } else { |
| 1869 // Only the least significant 5 bits of the shift value are used. | 2024 // Only the least significant 5 bits of the shift value are used. |
| 1870 // In the slow case, this masking is done inside the runtime call. | 2025 // In the slow case, this masking is done inside the runtime call. |
| 1871 int shift_value = int_value & 0x1f; | 2026 int shift_value = int_value & 0x1f; |
| 1872 operand->ToRegister(); | 2027 operand->ToRegister(); |
| 1873 if (shift_value == 0) { | 2028 if (shift_value == 0) { |
| 1874 // Spill operand so it can be overwritten in the slow case. | 2029 // Spill operand so it can be overwritten in the slow case. |
| 1875 frame_->Spill(operand->reg()); | 2030 frame_->Spill(operand->reg()); |
| 1876 DeferredInlineSmiOperation* deferred = | 2031 DeferredInlineSmiOperation* deferred = |
| 1877 new DeferredInlineSmiOperation(op, | 2032 new DeferredInlineSmiOperation(op, |
| 1878 operand->reg(), | 2033 operand->reg(), |
| 1879 operand->reg(), | 2034 operand->reg(), |
| 2035 operand->number_info(), |
| 1880 smi_value, | 2036 smi_value, |
| 1881 overwrite_mode); | 2037 overwrite_mode); |
| 1882 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2038 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 1883 deferred->Branch(not_zero); | 2039 deferred->Branch(not_zero); |
| 1884 deferred->BindExit(); | 2040 deferred->BindExit(); |
| 1885 answer = *operand; | 2041 answer = *operand; |
| 1886 } else { | 2042 } else { |
| 1887 // Use a fresh temporary for nonzero shift values. | 2043 // Use a fresh temporary for nonzero shift values. |
| 1888 answer = allocator()->Allocate(); | 2044 answer = allocator()->Allocate(); |
| 1889 ASSERT(answer.is_valid()); | 2045 ASSERT(answer.is_valid()); |
| 1890 DeferredInlineSmiOperation* deferred = | 2046 DeferredInlineSmiOperation* deferred = |
| 1891 new DeferredInlineSmiOperation(op, | 2047 new DeferredInlineSmiOperation(op, |
| 1892 answer.reg(), | 2048 answer.reg(), |
| 1893 operand->reg(), | 2049 operand->reg(), |
| 2050 operand->number_info(), |
| 1894 smi_value, | 2051 smi_value, |
| 1895 overwrite_mode); | 2052 overwrite_mode); |
| 1896 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2053 if (!operand->number_info().IsSmi()) { |
| 1897 deferred->Branch(not_zero); | 2054 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2055 deferred->Branch(not_zero); |
| 2056 } |
| 1898 __ mov(answer.reg(), operand->reg()); | 2057 __ mov(answer.reg(), operand->reg()); |
| 1899 ASSERT(kSmiTag == 0); // adjust code if not the case | 2058 ASSERT(kSmiTag == 0); // adjust code if not the case |
| 1900 // We do no shifts, only the Smi conversion, if shift_value is 1. | 2059 // We do no shifts, only the Smi conversion, if shift_value is 1. |
| 1901 if (shift_value > 1) { | 2060 if (shift_value > 1) { |
| 1902 __ shl(answer.reg(), shift_value - 1); | 2061 __ shl(answer.reg(), shift_value - 1); |
| 1903 } | 2062 } |
| 1904 // Convert int result to Smi, checking that it is in int range. | 2063 // Convert int result to Smi, checking that it is in int range. |
| 1905 ASSERT(kSmiTagSize == 1); // adjust code if not the case | 2064 ASSERT(kSmiTagSize == 1); // adjust code if not the case |
| 1906 __ add(answer.reg(), Operand(answer.reg())); | 2065 __ add(answer.reg(), Operand(answer.reg())); |
| 1907 deferred->Branch(overflow); | 2066 deferred->Branch(overflow); |
| 1908 deferred->BindExit(); | 2067 deferred->BindExit(); |
| 1909 operand->Unuse(); | 2068 operand->Unuse(); |
| 1910 } | 2069 } |
| 1911 } | 2070 } |
| 1912 break; | 2071 break; |
| 1913 | 2072 |
| 1914 case Token::BIT_OR: | 2073 case Token::BIT_OR: |
| 1915 case Token::BIT_XOR: | 2074 case Token::BIT_XOR: |
| 1916 case Token::BIT_AND: { | 2075 case Token::BIT_AND: { |
| 1917 operand->ToRegister(); | 2076 operand->ToRegister(); |
| 1918 frame_->Spill(operand->reg()); | 2077 frame_->Spill(operand->reg()); |
| 1919 DeferredCode* deferred = NULL; | 2078 DeferredCode* deferred = NULL; |
| 1920 if (reversed) { | 2079 if (reversed) { |
| 1921 deferred = new DeferredInlineSmiOperationReversed(op, | 2080 deferred = |
| 1922 operand->reg(), | 2081 new DeferredInlineSmiOperationReversed(op, |
| 1923 smi_value, | 2082 operand->reg(), |
| 1924 operand->reg(), | 2083 smi_value, |
| 1925 overwrite_mode); | 2084 operand->reg(), |
| 2085 operand->number_info(), |
| 2086 overwrite_mode); |
| 1926 } else { | 2087 } else { |
| 1927 deferred = new DeferredInlineSmiOperation(op, | 2088 deferred = new DeferredInlineSmiOperation(op, |
| 1928 operand->reg(), | 2089 operand->reg(), |
| 1929 operand->reg(), | 2090 operand->reg(), |
| 2091 operand->number_info(), |
| 1930 smi_value, | 2092 smi_value, |
| 1931 overwrite_mode); | 2093 overwrite_mode); |
| 1932 } | 2094 } |
| 1933 __ test(operand->reg(), Immediate(kSmiTagMask)); | 2095 if (!operand->number_info().IsSmi()) { |
| 1934 deferred->Branch(not_zero); | 2096 __ test(operand->reg(), Immediate(kSmiTagMask)); |
| 2097 deferred->Branch(not_zero); |
| 2098 } |
| 1935 if (op == Token::BIT_AND) { | 2099 if (op == Token::BIT_AND) { |
| 1936 __ and_(Operand(operand->reg()), Immediate(value)); | 2100 __ and_(Operand(operand->reg()), Immediate(value)); |
| 1937 } else if (op == Token::BIT_XOR) { | 2101 } else if (op == Token::BIT_XOR) { |
| 1938 if (int_value != 0) { | 2102 if (int_value != 0) { |
| 1939 __ xor_(Operand(operand->reg()), Immediate(value)); | 2103 __ xor_(Operand(operand->reg()), Immediate(value)); |
| 1940 } | 2104 } |
| 1941 } else { | 2105 } else { |
| 1942 ASSERT(op == Token::BIT_OR); | 2106 ASSERT(op == Token::BIT_OR); |
| 1943 if (int_value != 0) { | 2107 if (int_value != 0) { |
| 1944 __ or_(Operand(operand->reg()), Immediate(value)); | 2108 __ or_(Operand(operand->reg()), Immediate(value)); |
| 1945 } | 2109 } |
| 1946 } | 2110 } |
| 1947 deferred->BindExit(); | 2111 deferred->BindExit(); |
| 1948 answer = *operand; | 2112 answer = *operand; |
| 1949 break; | 2113 break; |
| 1950 } | 2114 } |
| 1951 | 2115 |
| 1952 case Token::DIV: | 2116 case Token::DIV: |
| 1953 if (!reversed && int_value == 2) { | 2117 if (!reversed && int_value == 2) { |
| 1954 operand->ToRegister(); | 2118 operand->ToRegister(); |
| 1955 frame_->Spill(operand->reg()); | 2119 frame_->Spill(operand->reg()); |
| 1956 | 2120 |
| 1957 DeferredInlineSmiOperation* deferred = | 2121 DeferredInlineSmiOperation* deferred = |
| 1958 new DeferredInlineSmiOperation(op, | 2122 new DeferredInlineSmiOperation(op, |
| 1959 operand->reg(), | 2123 operand->reg(), |
| 1960 operand->reg(), | 2124 operand->reg(), |
| 2125 operand->number_info(), |
| 1961 smi_value, | 2126 smi_value, |
| 1962 overwrite_mode); | 2127 overwrite_mode); |
| 1963 // Check that lowest log2(value) bits of operand are zero, and test | 2128 // Check that lowest log2(value) bits of operand are zero, and test |
| 1964 // smi tag at the same time. | 2129 // smi tag at the same time. |
| 1965 ASSERT_EQ(0, kSmiTag); | 2130 ASSERT_EQ(0, kSmiTag); |
| 1966 ASSERT_EQ(1, kSmiTagSize); | 2131 ASSERT_EQ(1, kSmiTagSize); |
| 1967 __ test(operand->reg(), Immediate(3)); | 2132 __ test(operand->reg(), Immediate(3)); |
| 1968 deferred->Branch(not_zero); // Branch if non-smi or odd smi. | 2133 deferred->Branch(not_zero); // Branch if non-smi or odd smi. |
| 1969 __ sar(operand->reg(), 1); | 2134 __ sar(operand->reg(), 1); |
| 1970 deferred->BindExit(); | 2135 deferred->BindExit(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1982 } | 2147 } |
| 1983 } | 2148 } |
| 1984 break; | 2149 break; |
| 1985 // Generate inline code for mod of powers of 2 and negative powers of 2. | 2150 // Generate inline code for mod of powers of 2 and negative powers of 2. |
| 1986 case Token::MOD: | 2151 case Token::MOD: |
| 1987 if (!reversed && | 2152 if (!reversed && |
| 1988 int_value != 0 && | 2153 int_value != 0 && |
| 1989 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { | 2154 (IsPowerOf2(int_value) || IsPowerOf2(-int_value))) { |
| 1990 operand->ToRegister(); | 2155 operand->ToRegister(); |
| 1991 frame_->Spill(operand->reg()); | 2156 frame_->Spill(operand->reg()); |
| 1992 DeferredCode* deferred = new DeferredInlineSmiOperation(op, | 2157 DeferredCode* deferred = |
| 1993 operand->reg(), | 2158 new DeferredInlineSmiOperation(op, |
| 1994 operand->reg(), | 2159 operand->reg(), |
| 1995 smi_value, | 2160 operand->reg(), |
| 1996 overwrite_mode); | 2161 operand->number_info(), |
| 2162 smi_value, |
| 2163 overwrite_mode); |
| 1997 // Check for negative or non-Smi left hand side. | 2164 // Check for negative or non-Smi left hand side. |
| 1998 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); | 2165 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 1999 deferred->Branch(not_zero); | 2166 deferred->Branch(not_zero); |
| 2000 if (int_value < 0) int_value = -int_value; | 2167 if (int_value < 0) int_value = -int_value; |
| 2001 if (int_value == 1) { | 2168 if (int_value == 1) { |
| 2002 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); | 2169 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); |
| 2003 } else { | 2170 } else { |
| 2004 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); | 2171 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); |
| 2005 } | 2172 } |
| 2006 deferred->BindExit(); | 2173 deferred->BindExit(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2020 } | 2187 } |
| 2021 break; | 2188 break; |
| 2022 } | 2189 } |
| 2023 } | 2190 } |
| 2024 ASSERT(answer.is_valid()); | 2191 ASSERT(answer.is_valid()); |
| 2025 return answer; | 2192 return answer; |
| 2026 } | 2193 } |
| 2027 | 2194 |
| 2028 | 2195 |
| 2029 static bool CouldBeNaN(const Result& result) { | 2196 static bool CouldBeNaN(const Result& result) { |
| 2197 if (result.number_info().IsSmi()) return false; |
| 2198 if (result.number_info().IsInteger32()) return false; |
| 2030 if (!result.is_constant()) return true; | 2199 if (!result.is_constant()) return true; |
| 2031 if (!result.handle()->IsHeapNumber()) return false; | 2200 if (!result.handle()->IsHeapNumber()) return false; |
| 2032 return isnan(HeapNumber::cast(*result.handle())->value()); | 2201 return isnan(HeapNumber::cast(*result.handle())->value()); |
| 2033 } | 2202 } |
| 2034 | 2203 |
| 2035 | 2204 |
| 2036 void CodeGenerator::Comparison(AstNode* node, | 2205 void CodeGenerator::Comparison(AstNode* node, |
| 2037 Condition cc, | 2206 Condition cc, |
| 2038 bool strict, | 2207 bool strict, |
| 2039 ControlDestination* dest) { | 2208 ControlDestination* dest) { |
| (...skipping 3375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5415 __ bind(&slow_case); | 5584 __ bind(&slow_case); |
| 5416 // Move the undefined value into the result register, which will | 5585 // Move the undefined value into the result register, which will |
| 5417 // trigger the slow case. | 5586 // trigger the slow case. |
| 5418 __ Set(temp.reg(), Immediate(Factory::undefined_value())); | 5587 __ Set(temp.reg(), Immediate(Factory::undefined_value())); |
| 5419 | 5588 |
| 5420 __ bind(&end); | 5589 __ bind(&end); |
| 5421 frame_->Push(&temp); | 5590 frame_->Push(&temp); |
| 5422 } | 5591 } |
| 5423 | 5592 |
| 5424 | 5593 |
| 5594 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { |
| 5595 Comment(masm_, "[ GenerateCharFromCode"); |
| 5596 ASSERT(args->length() == 1); |
| 5597 |
| 5598 Load(args->at(0)); |
| 5599 Result code = frame_->Pop(); |
| 5600 code.ToRegister(); |
| 5601 ASSERT(code.is_valid()); |
| 5602 |
| 5603 Result temp = allocator()->Allocate(); |
| 5604 ASSERT(temp.is_valid()); |
| 5605 |
| 5606 JumpTarget slow_case; |
| 5607 JumpTarget exit; |
| 5608 |
| 5609 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 5610 ASSERT(kSmiTag == 0); |
| 5611 ASSERT(kSmiShiftSize == 0); |
| 5612 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
| 5613 __ test(code.reg(), |
| 5614 Immediate(kSmiTagMask | |
| 5615 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 5616 slow_case.Branch(not_zero, &code, not_taken); |
| 5617 |
| 5618 __ Set(temp.reg(), Immediate(Factory::single_character_string_cache())); |
| 5619 ASSERT(kSmiTag == 0); |
| 5620 ASSERT(kSmiTagSize == 1); |
| 5621 ASSERT(kSmiShiftSize == 0); |
| 5622 // At this point code register contains smi tagged ascii char code. |
| 5623 __ mov(temp.reg(), FieldOperand(temp.reg(), |
| 5624 code.reg(), times_half_pointer_size, |
| 5625 FixedArray::kHeaderSize)); |
| 5626 __ cmp(temp.reg(), Factory::undefined_value()); |
| 5627 slow_case.Branch(equal, &code, not_taken); |
| 5628 code.Unuse(); |
| 5629 |
| 5630 frame_->Push(&temp); |
| 5631 exit.Jump(); |
| 5632 |
| 5633 slow_case.Bind(&code); |
| 5634 frame_->Push(&code); |
| 5635 Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1); |
| 5636 frame_->Push(&result); |
| 5637 |
| 5638 exit.Bind(); |
| 5639 } |
| 5640 |
| 5641 |
| 5425 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 5642 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 5426 ASSERT(args->length() == 1); | 5643 ASSERT(args->length() == 1); |
| 5427 Load(args->at(0)); | 5644 Load(args->at(0)); |
| 5428 Result value = frame_->Pop(); | 5645 Result value = frame_->Pop(); |
| 5429 value.ToRegister(); | 5646 value.ToRegister(); |
| 5430 ASSERT(value.is_valid()); | 5647 ASSERT(value.is_valid()); |
| 5431 __ test(value.reg(), Immediate(kSmiTagMask)); | 5648 __ test(value.reg(), Immediate(kSmiTagMask)); |
| 5432 destination()->false_target()->Branch(equal); | 5649 destination()->false_target()->Branch(equal); |
| 5433 // It is a heap object - get map. | 5650 // It is a heap object - get map. |
| 5434 Result temp = allocator()->Allocate(); | 5651 Result temp = allocator()->Allocate(); |
| (...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5735 ASSERT(ebp_as_smi.is_valid()); | 5952 ASSERT(ebp_as_smi.is_valid()); |
| 5736 __ mov(ebp_as_smi.reg(), Operand(ebp)); | 5953 __ mov(ebp_as_smi.reg(), Operand(ebp)); |
| 5737 frame_->Push(&ebp_as_smi); | 5954 frame_->Push(&ebp_as_smi); |
| 5738 } | 5955 } |
| 5739 | 5956 |
| 5740 | 5957 |
| 5741 void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { | 5958 void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { |
| 5742 ASSERT(args->length() == 0); | 5959 ASSERT(args->length() == 0); |
| 5743 frame_->SpillAll(); | 5960 frame_->SpillAll(); |
| 5744 | 5961 |
| 5745 // Make sure the frame is aligned like the OS expects. | 5962 static const int num_arguments = 0; |
| 5746 static const int kFrameAlignment = OS::ActivationFrameAlignment(); | 5963 __ PrepareCallCFunction(num_arguments, eax); |
| 5747 if (kFrameAlignment > 0) { | |
| 5748 ASSERT(IsPowerOf2(kFrameAlignment)); | |
| 5749 __ mov(edi, Operand(esp)); // Save in callee-saved register. | |
| 5750 __ and_(esp, -kFrameAlignment); | |
| 5751 } | |
| 5752 | 5964 |
| 5753 // Call V8::RandomPositiveSmi(). | 5965 // Call V8::RandomPositiveSmi(). |
| 5754 __ call(FUNCTION_ADDR(V8::RandomPositiveSmi), RelocInfo::RUNTIME_ENTRY); | 5966 __ CallCFunction(ExternalReference::random_positive_smi_function(), |
| 5755 | 5967 num_arguments); |
| 5756 // Restore stack pointer from callee-saved register edi. | |
| 5757 if (kFrameAlignment > 0) { | |
| 5758 __ mov(esp, Operand(edi)); | |
| 5759 } | |
| 5760 | 5968 |
| 5761 Result result = allocator_->Allocate(eax); | 5969 Result result = allocator_->Allocate(eax); |
| 5762 frame_->Push(&result); | 5970 frame_->Push(&result); |
| 5763 } | 5971 } |
| 5764 | 5972 |
| 5765 | 5973 |
| 5766 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { | 5974 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { |
| 5767 ASSERT_EQ(2, args->length()); | 5975 ASSERT_EQ(2, args->length()); |
| 5768 | 5976 |
| 5769 Load(args->at(0)); | 5977 Load(args->at(0)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5818 ASSERT_EQ(args->length(), 1); | 6026 ASSERT_EQ(args->length(), 1); |
| 5819 | 6027 |
| 5820 // Load the argument on the stack and call the stub. | 6028 // Load the argument on the stack and call the stub. |
| 5821 Load(args->at(0)); | 6029 Load(args->at(0)); |
| 5822 NumberToStringStub stub; | 6030 NumberToStringStub stub; |
| 5823 Result result = frame_->CallStub(&stub, 1); | 6031 Result result = frame_->CallStub(&stub, 1); |
| 5824 frame_->Push(&result); | 6032 frame_->Push(&result); |
| 5825 } | 6033 } |
| 5826 | 6034 |
| 5827 | 6035 |
| 6036 // Generates the Math.pow method - only handles special cases and branches to |
| 6037 // the runtime system if not.Please note - this function assumes that |
| 6038 // the callsite has executed ToNumber on both arguments and that the |
| 6039 // arguments are not the same identifier. |
| 6040 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
| 6041 ASSERT(args->length() == 2); |
| 6042 Load(args->at(0)); |
| 6043 Load(args->at(1)); |
| 6044 if (!CpuFeatures::IsSupported(SSE2)) { |
| 6045 Result res = frame_->CallRuntime(Runtime::kMath_pow, 2); |
| 6046 frame_->Push(&res); |
| 6047 } else { |
| 6048 CpuFeatures::Scope use_sse2(SSE2); |
| 6049 Label allocate_return; |
| 6050 // Load the two operands while leaving the values on the frame. |
| 6051 frame()->Dup(); |
| 6052 Result exponent = frame()->Pop(); |
| 6053 exponent.ToRegister(); |
| 6054 frame()->Spill(exponent.reg()); |
| 6055 frame()->PushElementAt(1); |
| 6056 Result base = frame()->Pop(); |
| 6057 base.ToRegister(); |
| 6058 frame()->Spill(base.reg()); |
| 6059 |
| 6060 Result answer = allocator()->Allocate(); |
| 6061 ASSERT(answer.is_valid()); |
| 6062 // We can safely assume that the base and exponent is not in the same |
| 6063 // register since we only call this from one callsite (math.js). |
| 6064 ASSERT(!exponent.reg().is(base.reg())); |
| 6065 JumpTarget call_runtime; |
| 6066 |
| 6067 // Save 1 in xmm3 - we need this several times later on. |
| 6068 __ mov(answer.reg(), Immediate(1)); |
| 6069 __ cvtsi2sd(xmm3, Operand(answer.reg())); |
| 6070 |
| 6071 Label exponent_nonsmi; |
| 6072 Label base_nonsmi; |
| 6073 // If the exponent is a heap number go to that specific case. |
| 6074 __ test(exponent.reg(), Immediate(kSmiTagMask)); |
| 6075 __ j(not_zero, &exponent_nonsmi); |
| 6076 __ test(base.reg(), Immediate(kSmiTagMask)); |
| 6077 __ j(not_zero, &base_nonsmi); |
| 6078 |
| 6079 // Optimized version when y is an integer. |
| 6080 Label powi; |
| 6081 __ SmiUntag(base.reg()); |
| 6082 __ cvtsi2sd(xmm0, Operand(base.reg())); |
| 6083 __ jmp(&powi); |
| 6084 // exponent is smi and base is a heapnumber. |
| 6085 __ bind(&base_nonsmi); |
| 6086 __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), |
| 6087 Factory::heap_number_map()); |
| 6088 call_runtime.Branch(not_equal); |
| 6089 |
| 6090 __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
| 6091 |
| 6092 // Optimized version of pow if y is an integer. |
| 6093 __ bind(&powi); |
| 6094 __ SmiUntag(exponent.reg()); |
| 6095 |
| 6096 // Save exponent in base as we need to check if exponent is negative later. |
| 6097 // We know that base and exponent are in different registers. |
| 6098 __ mov(base.reg(), exponent.reg()); |
| 6099 |
| 6100 // Get absolute value of exponent. |
| 6101 Label no_neg; |
| 6102 __ cmp(exponent.reg(), 0); |
| 6103 __ j(greater_equal, &no_neg); |
| 6104 __ neg(exponent.reg()); |
| 6105 __ bind(&no_neg); |
| 6106 |
| 6107 // Load xmm1 with 1. |
| 6108 __ movsd(xmm1, xmm3); |
| 6109 Label while_true; |
| 6110 Label no_multiply; |
| 6111 |
| 6112 // Label allocate_and_return; |
| 6113 __ bind(&while_true); |
| 6114 __ shr(exponent.reg(), 1); |
| 6115 __ j(not_carry, &no_multiply); |
| 6116 __ mulsd(xmm1, xmm0); |
| 6117 __ bind(&no_multiply); |
| 6118 __ test(exponent.reg(), Operand(exponent.reg())); |
| 6119 __ mulsd(xmm0, xmm0); |
| 6120 __ j(not_zero, &while_true); |
| 6121 |
| 6122 // x has the original value of y - if y is negative return 1/result. |
| 6123 __ test(base.reg(), Operand(base.reg())); |
| 6124 __ j(positive, &allocate_return); |
| 6125 // Special case if xmm1 has reached infinity. |
| 6126 __ mov(answer.reg(), Immediate(0x7FB00000)); |
| 6127 __ movd(xmm0, Operand(answer.reg())); |
| 6128 __ cvtss2sd(xmm0, xmm0); |
| 6129 __ ucomisd(xmm0, xmm1); |
| 6130 call_runtime.Branch(equal); |
| 6131 __ divsd(xmm3, xmm1); |
| 6132 __ movsd(xmm1, xmm3); |
| 6133 __ jmp(&allocate_return); |
| 6134 |
| 6135 // exponent (or both) is a heapnumber - no matter what we should now work |
| 6136 // on doubles. |
| 6137 __ bind(&exponent_nonsmi); |
| 6138 __ cmp(FieldOperand(exponent.reg(), HeapObject::kMapOffset), |
| 6139 Factory::heap_number_map()); |
| 6140 call_runtime.Branch(not_equal); |
| 6141 __ movdbl(xmm1, FieldOperand(exponent.reg(), HeapNumber::kValueOffset)); |
| 6142 // Test if exponent is nan. |
| 6143 __ ucomisd(xmm1, xmm1); |
| 6144 call_runtime.Branch(parity_even); |
| 6145 |
| 6146 Label base_not_smi; |
| 6147 Label handle_special_cases; |
| 6148 __ test(base.reg(), Immediate(kSmiTagMask)); |
| 6149 __ j(not_zero, &base_not_smi); |
| 6150 __ SmiUntag(base.reg()); |
| 6151 __ cvtsi2sd(xmm0, Operand(base.reg())); |
| 6152 __ jmp(&handle_special_cases); |
| 6153 __ bind(&base_not_smi); |
| 6154 __ cmp(FieldOperand(base.reg(), HeapObject::kMapOffset), |
| 6155 Factory::heap_number_map()); |
| 6156 call_runtime.Branch(not_equal); |
| 6157 __ mov(answer.reg(), FieldOperand(base.reg(), HeapNumber::kExponentOffset)); |
| 6158 __ and_(answer.reg(), HeapNumber::kExponentMask); |
| 6159 __ cmp(Operand(answer.reg()), Immediate(HeapNumber::kExponentMask)); |
| 6160 // base is NaN or +/-Infinity |
| 6161 call_runtime.Branch(greater_equal); |
| 6162 __ movdbl(xmm0, FieldOperand(base.reg(), HeapNumber::kValueOffset)); |
| 6163 |
| 6164 // base is in xmm0 and exponent is in xmm1. |
| 6165 __ bind(&handle_special_cases); |
| 6166 Label not_minus_half; |
| 6167 // Test for -0.5. |
| 6168 // Load xmm2 with -0.5. |
| 6169 __ mov(answer.reg(), Immediate(0xBF000000)); |
| 6170 __ movd(xmm2, Operand(answer.reg())); |
| 6171 __ cvtss2sd(xmm2, xmm2); |
| 6172 // xmm2 now has -0.5. |
| 6173 __ ucomisd(xmm2, xmm1); |
| 6174 __ j(not_equal, ¬_minus_half); |
| 6175 |
| 6176 // Calculates reciprocal of square root. |
| 6177 // Note that 1/sqrt(x) = sqrt(1/x)) |
| 6178 __ divsd(xmm3, xmm0); |
| 6179 __ movsd(xmm1, xmm3); |
| 6180 __ sqrtsd(xmm1, xmm1); |
| 6181 __ jmp(&allocate_return); |
| 6182 |
| 6183 // Test for 0.5. |
| 6184 __ bind(¬_minus_half); |
| 6185 // Load xmm2 with 0.5. |
| 6186 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. |
| 6187 __ addsd(xmm2, xmm3); |
| 6188 // xmm2 now has 0.5. |
| 6189 __ comisd(xmm2, xmm1); |
| 6190 call_runtime.Branch(not_equal); |
| 6191 // Calculates square root. |
| 6192 __ movsd(xmm1, xmm0); |
| 6193 __ sqrtsd(xmm1, xmm1); |
| 6194 |
| 6195 JumpTarget done; |
| 6196 Label failure, success; |
| 6197 __ bind(&allocate_return); |
| 6198 // Make a copy of the frame to enable us to handle allocation |
| 6199 // failure after the JumpTarget jump. |
| 6200 VirtualFrame* clone = new VirtualFrame(frame()); |
| 6201 __ AllocateHeapNumber(answer.reg(), exponent.reg(), |
| 6202 base.reg(), &failure); |
| 6203 __ movdbl(FieldOperand(answer.reg(), HeapNumber::kValueOffset), xmm1); |
| 6204 // Remove the two original values from the frame - we only need those |
| 6205 // in the case where we branch to runtime. |
| 6206 frame()->Drop(2); |
| 6207 exponent.Unuse(); |
| 6208 base.Unuse(); |
| 6209 done.Jump(&answer); |
| 6210 // Use the copy of the original frame as our current frame. |
| 6211 RegisterFile empty_regs; |
| 6212 SetFrame(clone, &empty_regs); |
| 6213 // If we experience an allocation failure we branch to runtime. |
| 6214 __ bind(&failure); |
| 6215 call_runtime.Bind(); |
| 6216 answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2); |
| 6217 |
| 6218 done.Bind(&answer); |
| 6219 frame()->Push(&answer); |
| 6220 } |
| 6221 } |
| 6222 |
| 6223 |
| 5828 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { | 6224 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
| 5829 ASSERT_EQ(args->length(), 1); | 6225 ASSERT_EQ(args->length(), 1); |
| 5830 Load(args->at(0)); | 6226 Load(args->at(0)); |
| 5831 TranscendentalCacheStub stub(TranscendentalCache::SIN); | 6227 TranscendentalCacheStub stub(TranscendentalCache::SIN); |
| 5832 Result result = frame_->CallStub(&stub, 1); | 6228 Result result = frame_->CallStub(&stub, 1); |
| 5833 frame_->Push(&result); | 6229 frame_->Push(&result); |
| 5834 } | 6230 } |
| 5835 | 6231 |
| 5836 | 6232 |
| 5837 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { | 6233 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { |
| 5838 ASSERT_EQ(args->length(), 1); | 6234 ASSERT_EQ(args->length(), 1); |
| 5839 Load(args->at(0)); | 6235 Load(args->at(0)); |
| 5840 TranscendentalCacheStub stub(TranscendentalCache::COS); | 6236 TranscendentalCacheStub stub(TranscendentalCache::COS); |
| 5841 Result result = frame_->CallStub(&stub, 1); | 6237 Result result = frame_->CallStub(&stub, 1); |
| 5842 frame_->Push(&result); | 6238 frame_->Push(&result); |
| 5843 } | 6239 } |
| 5844 | 6240 |
| 5845 | 6241 |
| 6242 // Generates the Math.sqrt method. Please note - this function assumes that |
| 6243 // the callsite has executed ToNumber on the argument. |
| 6244 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
| 6245 ASSERT_EQ(args->length(), 1); |
| 6246 Load(args->at(0)); |
| 6247 |
| 6248 if (!CpuFeatures::IsSupported(SSE2)) { |
| 6249 Result result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| 6250 frame()->Push(&result); |
| 6251 } else { |
| 6252 CpuFeatures::Scope use_sse2(SSE2); |
| 6253 // Leave original value on the frame if we need to call runtime. |
| 6254 frame()->Dup(); |
| 6255 Result result = frame()->Pop(); |
| 6256 result.ToRegister(); |
| 6257 frame()->Spill(result.reg()); |
| 6258 Label runtime; |
| 6259 Label non_smi; |
| 6260 Label load_done; |
| 6261 JumpTarget end; |
| 6262 |
| 6263 __ test(result.reg(), Immediate(kSmiTagMask)); |
| 6264 __ j(not_zero, &non_smi); |
| 6265 __ SmiUntag(result.reg()); |
| 6266 __ cvtsi2sd(xmm0, Operand(result.reg())); |
| 6267 __ jmp(&load_done); |
| 6268 __ bind(&non_smi); |
| 6269 __ cmp(FieldOperand(result.reg(), HeapObject::kMapOffset), |
| 6270 Factory::heap_number_map()); |
| 6271 __ j(not_equal, &runtime); |
| 6272 __ movdbl(xmm0, FieldOperand(result.reg(), HeapNumber::kValueOffset)); |
| 6273 |
| 6274 __ bind(&load_done); |
| 6275 __ sqrtsd(xmm0, xmm0); |
| 6276 // A copy of the virtual frame to allow us to go to runtime after the |
| 6277 // JumpTarget jump. |
| 6278 Result scratch = allocator()->Allocate(); |
| 6279 VirtualFrame* clone = new VirtualFrame(frame()); |
| 6280 __ AllocateHeapNumber(result.reg(), scratch.reg(), no_reg, &runtime); |
| 6281 |
| 6282 __ movdbl(FieldOperand(result.reg(), HeapNumber::kValueOffset), xmm0); |
| 6283 frame()->Drop(1); |
| 6284 scratch.Unuse(); |
| 6285 end.Jump(&result); |
| 6286 // We only branch to runtime if we have an allocation error. |
| 6287 // Use the copy of the original frame as our current frame. |
| 6288 RegisterFile empty_regs; |
| 6289 SetFrame(clone, &empty_regs); |
| 6290 __ bind(&runtime); |
| 6291 result = frame()->CallRuntime(Runtime::kMath_sqrt, 1); |
| 6292 |
| 6293 end.Bind(&result); |
| 6294 frame()->Push(&result); |
| 6295 } |
| 6296 } |
| 6297 |
| 6298 |
| 5846 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 6299 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
| 5847 if (CheckForInlineRuntimeCall(node)) { | 6300 if (CheckForInlineRuntimeCall(node)) { |
| 5848 return; | 6301 return; |
| 5849 } | 6302 } |
| 5850 | 6303 |
| 5851 ZoneList<Expression*>* args = node->arguments(); | 6304 ZoneList<Expression*>* args = node->arguments(); |
| 5852 Comment cmnt(masm_, "[ CallRuntime"); | 6305 Comment cmnt(masm_, "[ CallRuntime"); |
| 5853 Runtime::Function* function = node->function(); | 6306 Runtime::Function* function = node->function(); |
| 5854 | 6307 |
| 5855 if (function == NULL) { | 6308 if (function == NULL) { |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6695 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 7148 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); |
| 6696 | 7149 |
| 6697 if (!dst_.is(eax)) __ mov(dst_, eax); | 7150 if (!dst_.is(eax)) __ mov(dst_, eax); |
| 6698 } | 7151 } |
| 6699 | 7152 |
| 6700 | 7153 |
| 6701 class DeferredReferenceSetKeyedValue: public DeferredCode { | 7154 class DeferredReferenceSetKeyedValue: public DeferredCode { |
| 6702 public: | 7155 public: |
| 6703 DeferredReferenceSetKeyedValue(Register value, | 7156 DeferredReferenceSetKeyedValue(Register value, |
| 6704 Register key, | 7157 Register key, |
| 6705 Register receiver) | 7158 Register receiver, |
| 6706 : value_(value), key_(key), receiver_(receiver) { | 7159 Register scratch) |
| 7160 : value_(value), |
| 7161 key_(key), |
| 7162 receiver_(receiver), |
| 7163 scratch_(scratch) { |
| 6707 set_comment("[ DeferredReferenceSetKeyedValue"); | 7164 set_comment("[ DeferredReferenceSetKeyedValue"); |
| 6708 } | 7165 } |
| 6709 | 7166 |
| 6710 virtual void Generate(); | 7167 virtual void Generate(); |
| 6711 | 7168 |
| 6712 Label* patch_site() { return &patch_site_; } | 7169 Label* patch_site() { return &patch_site_; } |
| 6713 | 7170 |
| 6714 private: | 7171 private: |
| 6715 Register value_; | 7172 Register value_; |
| 6716 Register key_; | 7173 Register key_; |
| 6717 Register receiver_; | 7174 Register receiver_; |
| 7175 Register scratch_; |
| 6718 Label patch_site_; | 7176 Label patch_site_; |
| 6719 }; | 7177 }; |
| 6720 | 7178 |
| 6721 | 7179 |
| 6722 void DeferredReferenceSetKeyedValue::Generate() { | 7180 void DeferredReferenceSetKeyedValue::Generate() { |
| 6723 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 7181 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); |
| 6724 // Push receiver and key arguments on the stack. | 7182 // Move value_ to eax, key_ to ecx, and receiver_ to edx. |
| 6725 __ push(receiver_); | 7183 Register old_value = value_; |
| 6726 __ push(key_); | 7184 |
| 6727 // Move value argument to eax as expected by the IC stub. | 7185 // First, move value to eax. |
| 6728 if (!value_.is(eax)) __ mov(eax, value_); | 7186 if (!value_.is(eax)) { |
| 7187 if (key_.is(eax)) { |
| 7188 // Move key_ out of eax, preferably to ecx. |
| 7189 if (!value_.is(ecx) && !receiver_.is(ecx)) { |
| 7190 __ mov(ecx, key_); |
| 7191 key_ = ecx; |
| 7192 } else { |
| 7193 __ mov(scratch_, key_); |
| 7194 key_ = scratch_; |
| 7195 } |
| 7196 } |
| 7197 if (receiver_.is(eax)) { |
| 7198 // Move receiver_ out of eax, preferably to edx. |
| 7199 if (!value_.is(edx) && !key_.is(edx)) { |
| 7200 __ mov(edx, receiver_); |
| 7201 receiver_ = edx; |
| 7202 } else { |
| 7203 // Both moves to scratch are from eax, also, no valid path hits both. |
| 7204 __ mov(scratch_, receiver_); |
| 7205 receiver_ = scratch_; |
| 7206 } |
| 7207 } |
| 7208 __ mov(eax, value_); |
| 7209 value_ = eax; |
| 7210 } |
| 7211 |
| 7212 // Now value_ is in eax. Move the other two to the right positions. |
| 7213 // We do not update the variables key_ and receiver_ to ecx and edx. |
| 7214 if (key_.is(ecx)) { |
| 7215 if (!receiver_.is(edx)) { |
| 7216 __ mov(edx, receiver_); |
| 7217 } |
| 7218 } else if (key_.is(edx)) { |
| 7219 if (receiver_.is(ecx)) { |
| 7220 __ xchg(edx, ecx); |
| 7221 } else { |
| 7222 __ mov(ecx, key_); |
| 7223 if (!receiver_.is(edx)) { |
| 7224 __ mov(edx, receiver_); |
| 7225 } |
| 7226 } |
| 7227 } else { // Key is not in edx or ecx. |
| 7228 if (!receiver_.is(edx)) { |
| 7229 __ mov(edx, receiver_); |
| 7230 } |
| 7231 __ mov(ecx, key_); |
| 7232 } |
| 7233 |
| 6729 // Call the IC stub. | 7234 // Call the IC stub. |
| 6730 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 7235 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
| 6731 __ call(ic, RelocInfo::CODE_TARGET); | 7236 __ call(ic, RelocInfo::CODE_TARGET); |
| 6732 // The delta from the start of the map-compare instruction to the | 7237 // The delta from the start of the map-compare instruction to the |
| 6733 // test instruction. We use masm_-> directly here instead of the | 7238 // test instruction. We use masm_-> directly here instead of the |
| 6734 // __ macro because the macro sometimes uses macro expansion to turn | 7239 // __ macro because the macro sometimes uses macro expansion to turn |
| 6735 // into something that can't return a value. This is encountered | 7240 // into something that can't return a value. This is encountered |
| 6736 // when doing generated code coverage tests. | 7241 // when doing generated code coverage tests. |
| 6737 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 7242 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
| 6738 // Here we use masm_-> instead of the __ macro because this is the | 7243 // Here we use masm_-> instead of the __ macro because this is the |
| 6739 // instruction that gets patched and coverage code gets in the way. | 7244 // instruction that gets patched and coverage code gets in the way. |
| 6740 masm_->test(eax, Immediate(-delta_to_patch_site)); | 7245 masm_->test(eax, Immediate(-delta_to_patch_site)); |
| 6741 // Restore value (returned from store IC), key and receiver | 7246 // Restore value (returned from store IC) register. |
| 6742 // registers. | 7247 if (!old_value.is(eax)) __ mov(old_value, eax); |
| 6743 if (!value_.is(eax)) __ mov(value_, eax); | |
| 6744 __ pop(key_); | |
| 6745 __ pop(receiver_); | |
| 6746 } | 7248 } |
| 6747 | 7249 |
| 6748 | 7250 |
| 6749 Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { | 7251 Result CodeGenerator::EmitNamedLoad(Handle<String> name, bool is_contextual) { |
| 6750 #ifdef DEBUG | 7252 #ifdef DEBUG |
| 6751 int original_height = frame()->height(); | 7253 int original_height = frame()->height(); |
| 6752 #endif | 7254 #endif |
| 6753 Result result; | 7255 Result result; |
| 6754 // Do not inline the inobject property case for loads from the global | 7256 // Do not inline the inobject property case for loads from the global |
| 6755 // object. Also do not inline for unoptimized code. This saves time in | 7257 // object. Also do not inline for unoptimized code. This saves time in |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6859 // Initially, use an invalid map. The map is patched in the IC | 7361 // Initially, use an invalid map. The map is patched in the IC |
| 6860 // initialization code. | 7362 // initialization code. |
| 6861 __ bind(deferred->patch_site()); | 7363 __ bind(deferred->patch_site()); |
| 6862 // Use masm-> here instead of the double underscore macro since extra | 7364 // Use masm-> here instead of the double underscore macro since extra |
| 6863 // coverage code can interfere with the patching. | 7365 // coverage code can interfere with the patching. |
| 6864 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 7366 masm_->cmp(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
| 6865 Immediate(Factory::null_value())); | 7367 Immediate(Factory::null_value())); |
| 6866 deferred->Branch(not_equal); | 7368 deferred->Branch(not_equal); |
| 6867 | 7369 |
| 6868 // Check that the key is a smi. | 7370 // Check that the key is a smi. |
| 6869 __ test(key.reg(), Immediate(kSmiTagMask)); | 7371 if (!key.is_smi()) { |
| 6870 deferred->Branch(not_zero); | 7372 __ test(key.reg(), Immediate(kSmiTagMask)); |
| 7373 deferred->Branch(not_zero); |
| 7374 } |
| 6871 | 7375 |
| 6872 // Get the elements array from the receiver and check that it | 7376 // Get the elements array from the receiver and check that it |
| 6873 // is not a dictionary. | 7377 // is not a dictionary. |
| 6874 __ mov(elements.reg(), | 7378 __ mov(elements.reg(), |
| 6875 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | 7379 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); |
| 6876 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), | 7380 __ cmp(FieldOperand(elements.reg(), HeapObject::kMapOffset), |
| 6877 Immediate(Factory::fixed_array_map())); | 7381 Immediate(Factory::fixed_array_map())); |
| 6878 deferred->Branch(not_equal); | 7382 deferred->Branch(not_equal); |
| 6879 | 7383 |
| 6880 // Shift the key to get the actual index value and check that | 7384 // Shift the key to get the actual index value and check that |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6934 bool value_is_constant = result.is_constant(); | 7438 bool value_is_constant = result.is_constant(); |
| 6935 | 7439 |
| 6936 // Make sure that value, key and receiver are in registers. | 7440 // Make sure that value, key and receiver are in registers. |
| 6937 result.ToRegister(); | 7441 result.ToRegister(); |
| 6938 key.ToRegister(); | 7442 key.ToRegister(); |
| 6939 receiver.ToRegister(); | 7443 receiver.ToRegister(); |
| 6940 | 7444 |
| 6941 DeferredReferenceSetKeyedValue* deferred = | 7445 DeferredReferenceSetKeyedValue* deferred = |
| 6942 new DeferredReferenceSetKeyedValue(result.reg(), | 7446 new DeferredReferenceSetKeyedValue(result.reg(), |
| 6943 key.reg(), | 7447 key.reg(), |
| 6944 receiver.reg()); | 7448 receiver.reg(), |
| 7449 tmp.reg()); |
| 6945 | 7450 |
| 6946 // Check that the value is a smi if it is not a constant. We can skip | 7451 // Check that the value is a smi if it is not a constant. We can skip |
| 6947 // the write barrier for smis and constants. | 7452 // the write barrier for smis and constants. |
| 6948 if (!value_is_constant) { | 7453 if (!value_is_constant) { |
| 6949 __ test(result.reg(), Immediate(kSmiTagMask)); | 7454 __ test(result.reg(), Immediate(kSmiTagMask)); |
| 6950 deferred->Branch(not_zero); | 7455 deferred->Branch(not_zero); |
| 6951 } | 7456 } |
| 6952 | 7457 |
| 6953 // Check that the key is a non-negative smi. | 7458 // Check that the key is a non-negative smi. |
| 6954 __ test(key.reg(), Immediate(kSmiTagMask | 0x80000000)); | 7459 __ test(key.reg(), Immediate(kSmiTagMask | 0x80000000)); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6994 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 7499 __ IncrementCounter(&Counters::keyed_store_inline, 1); |
| 6995 | 7500 |
| 6996 deferred->BindExit(); | 7501 deferred->BindExit(); |
| 6997 } else { | 7502 } else { |
| 6998 result = frame()->CallKeyedStoreIC(); | 7503 result = frame()->CallKeyedStoreIC(); |
| 6999 // Make sure that we do not have a test instruction after the | 7504 // Make sure that we do not have a test instruction after the |
| 7000 // call. A test instruction after the call is used to | 7505 // call. A test instruction after the call is used to |
| 7001 // indicate that we have generated an inline version of the | 7506 // indicate that we have generated an inline version of the |
| 7002 // keyed store. | 7507 // keyed store. |
| 7003 __ nop(); | 7508 __ nop(); |
| 7004 frame()->Drop(2); | |
| 7005 } | 7509 } |
| 7006 ASSERT(frame()->height() == original_height - 3); | 7510 ASSERT(frame()->height() == original_height - 3); |
| 7007 return result; | 7511 return result; |
| 7008 } | 7512 } |
| 7009 | 7513 |
| 7010 | 7514 |
| 7011 #undef __ | 7515 #undef __ |
| 7012 #define __ ACCESS_MASM(masm) | 7516 #define __ ACCESS_MASM(masm) |
| 7013 | 7517 |
| 7014 | 7518 |
| 7519 static void CheckTwoForSminess(MacroAssembler* masm, |
| 7520 Register left, Register right, Register scratch, |
| 7521 NumberInfo left_info, NumberInfo right_info, |
| 7522 DeferredInlineBinaryOperation* deferred) { |
| 7523 if (left.is(right)) { |
| 7524 if (!left_info.IsSmi()) { |
| 7525 __ test(left, Immediate(kSmiTagMask)); |
| 7526 deferred->Branch(not_zero); |
| 7527 } |
| 7528 } else if (!left_info.IsSmi()) { |
| 7529 if (!right_info.IsSmi()) { |
| 7530 __ mov(scratch, left); |
| 7531 __ or_(scratch, Operand(right)); |
| 7532 __ test(scratch, Immediate(kSmiTagMask)); |
| 7533 deferred->Branch(not_zero); |
| 7534 } else { |
| 7535 __ test(left, Immediate(kSmiTagMask)); |
| 7536 deferred->Branch(not_zero); |
| 7537 } |
| 7538 } else { |
| 7539 if (!right_info.IsSmi()) { |
| 7540 __ test(right, Immediate(kSmiTagMask)); |
| 7541 deferred->Branch(not_zero); |
| 7542 } |
| 7543 } |
| 7544 } |
| 7545 |
| 7546 |
| 7015 Handle<String> Reference::GetName() { | 7547 Handle<String> Reference::GetName() { |
| 7016 ASSERT(type_ == NAMED); | 7548 ASSERT(type_ == NAMED); |
| 7017 Property* property = expression_->AsProperty(); | 7549 Property* property = expression_->AsProperty(); |
| 7018 if (property == NULL) { | 7550 if (property == NULL) { |
| 7019 // Global variable reference treated as a named property reference. | 7551 // Global variable reference treated as a named property reference. |
| 7020 VariableProxy* proxy = expression_->AsVariableProxy(); | 7552 VariableProxy* proxy = expression_->AsVariableProxy(); |
| 7021 ASSERT(proxy->AsVariable() != NULL); | 7553 ASSERT(proxy->AsVariable() != NULL); |
| 7022 ASSERT(proxy->AsVariable()->is_global()); | 7554 ASSERT(proxy->AsVariable()->is_global()); |
| 7023 return proxy->name(); | 7555 return proxy->name(); |
| 7024 } else { | 7556 } else { |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7136 Result answer = cgen_->EmitNamedStore(GetName(), false); | 7668 Result answer = cgen_->EmitNamedStore(GetName(), false); |
| 7137 cgen_->frame()->Push(&answer); | 7669 cgen_->frame()->Push(&answer); |
| 7138 set_unloaded(); | 7670 set_unloaded(); |
| 7139 break; | 7671 break; |
| 7140 } | 7672 } |
| 7141 | 7673 |
| 7142 case KEYED: { | 7674 case KEYED: { |
| 7143 Comment cmnt(masm, "[ Store to keyed Property"); | 7675 Comment cmnt(masm, "[ Store to keyed Property"); |
| 7144 Property* property = expression()->AsProperty(); | 7676 Property* property = expression()->AsProperty(); |
| 7145 ASSERT(property != NULL); | 7677 ASSERT(property != NULL); |
| 7678 |
| 7146 Result answer = cgen_->EmitKeyedStore(property->key()->type()); | 7679 Result answer = cgen_->EmitKeyedStore(property->key()->type()); |
| 7147 cgen_->frame()->Push(&answer); | 7680 cgen_->frame()->Push(&answer); |
| 7148 set_unloaded(); | 7681 set_unloaded(); |
| 7149 break; | 7682 break; |
| 7150 } | 7683 } |
| 7151 | 7684 |
| 7152 case UNLOADED: | 7685 case UNLOADED: |
| 7153 case ILLEGAL: | 7686 case ILLEGAL: |
| 7154 UNREACHABLE(); | 7687 UNREACHABLE(); |
| 7155 } | 7688 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7188 // Return and remove the on-stack parameter. | 7721 // Return and remove the on-stack parameter. |
| 7189 __ ret(1 * kPointerSize); | 7722 __ ret(1 * kPointerSize); |
| 7190 | 7723 |
| 7191 // Create a new closure through the slower runtime call. | 7724 // Create a new closure through the slower runtime call. |
| 7192 __ bind(&gc); | 7725 __ bind(&gc); |
| 7193 __ pop(ecx); // Temporarily remove return address. | 7726 __ pop(ecx); // Temporarily remove return address. |
| 7194 __ pop(edx); | 7727 __ pop(edx); |
| 7195 __ push(esi); | 7728 __ push(esi); |
| 7196 __ push(edx); | 7729 __ push(edx); |
| 7197 __ push(ecx); // Restore return address. | 7730 __ push(ecx); // Restore return address. |
| 7198 __ TailCallRuntime(ExternalReference(Runtime::kNewClosure), 2, 1); | 7731 __ TailCallRuntime(Runtime::kNewClosure, 2, 1); |
| 7199 } | 7732 } |
| 7200 | 7733 |
| 7201 | 7734 |
| 7202 void FastNewContextStub::Generate(MacroAssembler* masm) { | 7735 void FastNewContextStub::Generate(MacroAssembler* masm) { |
| 7203 // Try to allocate the context in new space. | 7736 // Try to allocate the context in new space. |
| 7204 Label gc; | 7737 Label gc; |
| 7205 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 7738 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 7206 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, | 7739 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, |
| 7207 eax, ebx, ecx, &gc, TAG_OBJECT); | 7740 eax, ebx, ecx, &gc, TAG_OBJECT); |
| 7208 | 7741 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 7232 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 7765 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 7233 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); | 7766 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); |
| 7234 } | 7767 } |
| 7235 | 7768 |
| 7236 // Return and remove the on-stack parameter. | 7769 // Return and remove the on-stack parameter. |
| 7237 __ mov(esi, Operand(eax)); | 7770 __ mov(esi, Operand(eax)); |
| 7238 __ ret(1 * kPointerSize); | 7771 __ ret(1 * kPointerSize); |
| 7239 | 7772 |
| 7240 // Need to collect. Call into runtime system. | 7773 // Need to collect. Call into runtime system. |
| 7241 __ bind(&gc); | 7774 __ bind(&gc); |
| 7242 __ TailCallRuntime(ExternalReference(Runtime::kNewContext), 1, 1); | 7775 __ TailCallRuntime(Runtime::kNewContext, 1, 1); |
| 7243 } | 7776 } |
| 7244 | 7777 |
| 7245 | 7778 |
| 7246 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 7779 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 7247 // Stack layout on entry: | 7780 // Stack layout on entry: |
| 7248 // | 7781 // |
| 7249 // [esp + kPointerSize]: constant elements. | 7782 // [esp + kPointerSize]: constant elements. |
| 7250 // [esp + (2 * kPointerSize)]: literal index. | 7783 // [esp + (2 * kPointerSize)]: literal index. |
| 7251 // [esp + (3 * kPointerSize)]: literals array. | 7784 // [esp + (3 * kPointerSize)]: literals array. |
| 7252 | 7785 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7287 for (int i = 0; i < elements_size; i += kPointerSize) { | 7820 for (int i = 0; i < elements_size; i += kPointerSize) { |
| 7288 __ mov(ebx, FieldOperand(ecx, i)); | 7821 __ mov(ebx, FieldOperand(ecx, i)); |
| 7289 __ mov(FieldOperand(edx, i), ebx); | 7822 __ mov(FieldOperand(edx, i), ebx); |
| 7290 } | 7823 } |
| 7291 } | 7824 } |
| 7292 | 7825 |
| 7293 // Return and remove the on-stack parameters. | 7826 // Return and remove the on-stack parameters. |
| 7294 __ ret(3 * kPointerSize); | 7827 __ ret(3 * kPointerSize); |
| 7295 | 7828 |
| 7296 __ bind(&slow_case); | 7829 __ bind(&slow_case); |
| 7297 ExternalReference runtime(Runtime::kCreateArrayLiteralShallow); | 7830 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 7298 __ TailCallRuntime(runtime, 3, 1); | |
| 7299 } | 7831 } |
| 7300 | 7832 |
| 7301 | 7833 |
| 7302 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). | 7834 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). |
| 7303 void ToBooleanStub::Generate(MacroAssembler* masm) { | 7835 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 7304 Label false_result, true_result, not_string; | 7836 Label false_result, true_result, not_string; |
| 7305 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 7837 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 7306 | 7838 |
| 7307 // 'null' => false. | 7839 // 'null' => false. |
| 7308 __ cmp(eax, Factory::null_value()); | 7840 __ cmp(eax, Factory::null_value()); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7505 if (HasArgsInRegisters()) { | 8037 if (HasArgsInRegisters()) { |
| 7506 __ mov(ebx, eax); | 8038 __ mov(ebx, eax); |
| 7507 __ mov(eax, edx); | 8039 __ mov(eax, edx); |
| 7508 } | 8040 } |
| 7509 } | 8041 } |
| 7510 if (!HasArgsInRegisters()) { | 8042 if (!HasArgsInRegisters()) { |
| 7511 __ mov(right, Operand(esp, 1 * kPointerSize)); | 8043 __ mov(right, Operand(esp, 1 * kPointerSize)); |
| 7512 __ mov(left, Operand(esp, 2 * kPointerSize)); | 8044 __ mov(left, Operand(esp, 2 * kPointerSize)); |
| 7513 } | 8045 } |
| 7514 | 8046 |
| 8047 if (static_operands_type_.IsSmi()) { |
| 8048 if (op_ == Token::BIT_OR) { |
| 8049 __ or_(right, Operand(left)); |
| 8050 GenerateReturn(masm); |
| 8051 return; |
| 8052 } else if (op_ == Token::BIT_AND) { |
| 8053 __ and_(right, Operand(left)); |
| 8054 GenerateReturn(masm); |
| 8055 return; |
| 8056 } else if (op_ == Token::BIT_XOR) { |
| 8057 __ xor_(right, Operand(left)); |
| 8058 GenerateReturn(masm); |
| 8059 return; |
| 8060 } |
| 8061 } |
| 8062 |
| 7515 // 2. Prepare the smi check of both operands by oring them together. | 8063 // 2. Prepare the smi check of both operands by oring them together. |
| 7516 Comment smi_check_comment(masm, "-- Smi check arguments"); | 8064 Comment smi_check_comment(masm, "-- Smi check arguments"); |
| 7517 Label not_smis; | 8065 Label not_smis; |
| 7518 Register combined = ecx; | 8066 Register combined = ecx; |
| 7519 ASSERT(!left.is(combined) && !right.is(combined)); | 8067 ASSERT(!left.is(combined) && !right.is(combined)); |
| 7520 switch (op_) { | 8068 switch (op_) { |
| 7521 case Token::BIT_OR: | 8069 case Token::BIT_OR: |
| 7522 // Perform the operation into eax and smi check the result. Preserve | 8070 // Perform the operation into eax and smi check the result. Preserve |
| 7523 // eax in case the result is not a smi. | 8071 // eax in case the result is not a smi. |
| 7524 ASSERT(!left.is(ecx) && !right.is(ecx)); | 8072 ASSERT(!left.is(ecx) && !right.is(ecx)); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7813 | 8361 |
| 7814 | 8362 |
| 7815 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 8363 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| 7816 Label call_runtime; | 8364 Label call_runtime; |
| 7817 | 8365 |
| 7818 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | 8366 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); |
| 7819 | 8367 |
| 7820 // Generate fast case smi code if requested. This flag is set when the fast | 8368 // Generate fast case smi code if requested. This flag is set when the fast |
| 7821 // case smi code is not generated by the caller. Generating it here will speed | 8369 // case smi code is not generated by the caller. Generating it here will speed |
| 7822 // up common operations. | 8370 // up common operations. |
| 7823 if (HasSmiCodeInStub()) { | 8371 if (ShouldGenerateSmiCode()) { |
| 7824 GenerateSmiCode(masm, &call_runtime); | 8372 GenerateSmiCode(masm, &call_runtime); |
| 7825 } else if (op_ != Token::MOD) { // MOD goes straight to runtime. | 8373 } else if (op_ != Token::MOD) { // MOD goes straight to runtime. |
| 7826 GenerateLoadArguments(masm); | 8374 if (!HasArgsInRegisters()) { |
| 8375 GenerateLoadArguments(masm); |
| 8376 } |
| 7827 } | 8377 } |
| 7828 | 8378 |
| 7829 // Floating point case. | 8379 // Floating point case. |
| 7830 switch (op_) { | 8380 if (ShouldGenerateFPCode()) { |
| 7831 case Token::ADD: | 8381 switch (op_) { |
| 7832 case Token::SUB: | 8382 case Token::ADD: |
| 7833 case Token::MUL: | 8383 case Token::SUB: |
| 7834 case Token::DIV: { | 8384 case Token::MUL: |
| 7835 if (CpuFeatures::IsSupported(SSE2)) { | 8385 case Token::DIV: { |
| 7836 CpuFeatures::Scope use_sse2(SSE2); | 8386 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
| 7837 if (NumberInfo::IsNumber(operands_type_)) { | 8387 HasSmiCodeInStub()) { |
| 7838 if (FLAG_debug_code) { | 8388 // Execution reaches this point when the first non-smi argument occurs |
| 7839 // Assert at runtime that inputs are only numbers. | 8389 // (and only if smi code is generated). This is the right moment to |
| 7840 __ AbortIfNotNumber(edx, | 8390 // patch to HEAP_NUMBERS state. The transition is attempted only for |
| 7841 "GenericBinaryOpStub operand not a number."); | 8391 // the four basic operations. The stub stays in the DEFAULT state |
| 7842 __ AbortIfNotNumber(eax, | 8392 // forever for all other operations (also if smi code is skipped). |
| 7843 "GenericBinaryOpStub operand not a number."); | 8393 GenerateTypeTransition(masm); |
| 7844 } | |
| 7845 FloatingPointHelper::LoadSSE2Operands(masm); | |
| 7846 } else { | |
| 7847 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); | |
| 7848 } | 8394 } |
| 7849 | 8395 |
| 8396 Label not_floats; |
| 8397 if (CpuFeatures::IsSupported(SSE2)) { |
| 8398 CpuFeatures::Scope use_sse2(SSE2); |
| 8399 if (static_operands_type_.IsNumber()) { |
| 8400 if (FLAG_debug_code) { |
| 8401 // Assert at runtime that inputs are only numbers. |
| 8402 __ AbortIfNotNumber(edx, |
| 8403 "GenericBinaryOpStub operand not a number."); |
| 8404 __ AbortIfNotNumber(eax, |
| 8405 "GenericBinaryOpStub operand not a number."); |
| 8406 } |
| 8407 if (static_operands_type_.IsSmi()) { |
| 8408 FloatingPointHelper::LoadSSE2Smis(masm, ecx); |
| 8409 } else { |
| 8410 FloatingPointHelper::LoadSSE2Operands(masm); |
| 8411 } |
| 8412 } else { |
| 8413 FloatingPointHelper::LoadSSE2Operands(masm, &call_runtime); |
| 8414 } |
| 8415 |
| 8416 switch (op_) { |
| 8417 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 8418 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 8419 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 8420 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 8421 default: UNREACHABLE(); |
| 8422 } |
| 8423 GenerateHeapResultAllocation(masm, &call_runtime); |
| 8424 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 8425 GenerateReturn(masm); |
| 8426 } else { // SSE2 not available, use FPU. |
| 8427 if (static_operands_type_.IsNumber()) { |
| 8428 if (FLAG_debug_code) { |
| 8429 // Assert at runtime that inputs are only numbers. |
| 8430 __ AbortIfNotNumber(edx, |
| 8431 "GenericBinaryOpStub operand not a number."); |
| 8432 __ AbortIfNotNumber(eax, |
| 8433 "GenericBinaryOpStub operand not a number."); |
| 8434 } |
| 8435 } else { |
| 8436 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); |
| 8437 } |
| 8438 FloatingPointHelper::LoadFloatOperands( |
| 8439 masm, |
| 8440 ecx, |
| 8441 FloatingPointHelper::ARGS_IN_REGISTERS); |
| 8442 switch (op_) { |
| 8443 case Token::ADD: __ faddp(1); break; |
| 8444 case Token::SUB: __ fsubp(1); break; |
| 8445 case Token::MUL: __ fmulp(1); break; |
| 8446 case Token::DIV: __ fdivp(1); break; |
| 8447 default: UNREACHABLE(); |
| 8448 } |
| 8449 Label after_alloc_failure; |
| 8450 GenerateHeapResultAllocation(masm, &after_alloc_failure); |
| 8451 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 8452 GenerateReturn(masm); |
| 8453 __ bind(&after_alloc_failure); |
| 8454 __ ffree(); |
| 8455 __ jmp(&call_runtime); |
| 8456 } |
| 8457 __ bind(¬_floats); |
| 8458 if (runtime_operands_type_ == BinaryOpIC::DEFAULT && |
| 8459 !HasSmiCodeInStub()) { |
| 8460 // Execution reaches this point when the first non-number argument |
| 8461 // occurs (and only if smi code is skipped from the stub, otherwise |
| 8462 // the patching has already been done earlier in this case branch). |
| 8463 // Try patching to STRINGS for ADD operation. |
| 8464 if (op_ == Token::ADD) { |
| 8465 GenerateTypeTransition(masm); |
| 8466 } |
| 8467 } |
| 8468 break; |
| 8469 } |
| 8470 case Token::MOD: { |
| 8471 // For MOD we go directly to runtime in the non-smi case. |
| 8472 break; |
| 8473 } |
| 8474 case Token::BIT_OR: |
| 8475 case Token::BIT_AND: |
| 8476 case Token::BIT_XOR: |
| 8477 case Token::SAR: |
| 8478 case Token::SHL: |
| 8479 case Token::SHR: { |
| 8480 Label non_smi_result; |
| 8481 FloatingPointHelper::LoadAsIntegers(masm, |
| 8482 static_operands_type_, |
| 8483 use_sse3_, |
| 8484 &call_runtime); |
| 7850 switch (op_) { | 8485 switch (op_) { |
| 7851 case Token::ADD: __ addsd(xmm0, xmm1); break; | 8486 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; |
| 7852 case Token::SUB: __ subsd(xmm0, xmm1); break; | 8487 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; |
| 7853 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 8488 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; |
| 7854 case Token::DIV: __ divsd(xmm0, xmm1); break; | 8489 case Token::SAR: __ sar_cl(eax); break; |
| 8490 case Token::SHL: __ shl_cl(eax); break; |
| 8491 case Token::SHR: __ shr_cl(eax); break; |
| 7855 default: UNREACHABLE(); | 8492 default: UNREACHABLE(); |
| 7856 } | 8493 } |
| 7857 GenerateHeapResultAllocation(masm, &call_runtime); | 8494 if (op_ == Token::SHR) { |
| 7858 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 8495 // Check if result is non-negative and fits in a smi. |
| 8496 __ test(eax, Immediate(0xc0000000)); |
| 8497 __ j(not_zero, &call_runtime); |
| 8498 } else { |
| 8499 // Check if result fits in a smi. |
| 8500 __ cmp(eax, 0xc0000000); |
| 8501 __ j(negative, &non_smi_result); |
| 8502 } |
| 8503 // Tag smi result and return. |
| 8504 __ SmiTag(eax); |
| 7859 GenerateReturn(masm); | 8505 GenerateReturn(masm); |
| 7860 } else { // SSE2 not available, use FPU. | 8506 |
| 7861 if (NumberInfo::IsNumber(operands_type_)) { | 8507 // All ops except SHR return a signed int32 that we load in |
| 7862 if (FLAG_debug_code) { | 8508 // a HeapNumber. |
| 7863 // Assert at runtime that inputs are only numbers. | 8509 if (op_ != Token::SHR) { |
| 7864 __ AbortIfNotNumber(edx, | 8510 __ bind(&non_smi_result); |
| 7865 "GenericBinaryOpStub operand not a number."); | 8511 // Allocate a heap number if needed. |
| 7866 __ AbortIfNotNumber(eax, | 8512 __ mov(ebx, Operand(eax)); // ebx: result |
| 7867 "GenericBinaryOpStub operand not a number."); | 8513 Label skip_allocation; |
| 8514 switch (mode_) { |
| 8515 case OVERWRITE_LEFT: |
| 8516 case OVERWRITE_RIGHT: |
| 8517 // If the operand was an object, we skip the |
| 8518 // allocation of a heap number. |
| 8519 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? |
| 8520 1 * kPointerSize : 2 * kPointerSize)); |
| 8521 __ test(eax, Immediate(kSmiTagMask)); |
| 8522 __ j(not_zero, &skip_allocation, not_taken); |
| 8523 // Fall through! |
| 8524 case NO_OVERWRITE: |
| 8525 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 8526 __ bind(&skip_allocation); |
| 8527 break; |
| 8528 default: UNREACHABLE(); |
| 7868 } | 8529 } |
| 7869 } else { | 8530 // Store the result in the HeapNumber and return. |
| 7870 FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx); | 8531 if (CpuFeatures::IsSupported(SSE2)) { |
| 8532 CpuFeatures::Scope use_sse2(SSE2); |
| 8533 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 8534 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 8535 } else { |
| 8536 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 8537 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 8538 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 8539 } |
| 8540 GenerateReturn(masm); |
| 7871 } | 8541 } |
| 7872 FloatingPointHelper::LoadFloatOperands( | 8542 break; |
| 7873 masm, | |
| 7874 ecx, | |
| 7875 FloatingPointHelper::ARGS_IN_REGISTERS); | |
| 7876 switch (op_) { | |
| 7877 case Token::ADD: __ faddp(1); break; | |
| 7878 case Token::SUB: __ fsubp(1); break; | |
| 7879 case Token::MUL: __ fmulp(1); break; | |
| 7880 case Token::DIV: __ fdivp(1); break; | |
| 7881 default: UNREACHABLE(); | |
| 7882 } | |
| 7883 Label after_alloc_failure; | |
| 7884 GenerateHeapResultAllocation(masm, &after_alloc_failure); | |
| 7885 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 7886 GenerateReturn(masm); | |
| 7887 __ bind(&after_alloc_failure); | |
| 7888 __ ffree(); | |
| 7889 __ jmp(&call_runtime); | |
| 7890 } | 8543 } |
| 8544 default: UNREACHABLE(); break; |
| 7891 } | 8545 } |
| 7892 case Token::MOD: { | |
| 7893 // For MOD we go directly to runtime in the non-smi case. | |
| 7894 break; | |
| 7895 } | |
| 7896 case Token::BIT_OR: | |
| 7897 case Token::BIT_AND: | |
| 7898 case Token::BIT_XOR: | |
| 7899 case Token::SAR: | |
| 7900 case Token::SHL: | |
| 7901 case Token::SHR: { | |
| 7902 Label non_smi_result; | |
| 7903 FloatingPointHelper::LoadAsIntegers(masm, use_sse3_, &call_runtime); | |
| 7904 switch (op_) { | |
| 7905 case Token::BIT_OR: __ or_(eax, Operand(ecx)); break; | |
| 7906 case Token::BIT_AND: __ and_(eax, Operand(ecx)); break; | |
| 7907 case Token::BIT_XOR: __ xor_(eax, Operand(ecx)); break; | |
| 7908 case Token::SAR: __ sar_cl(eax); break; | |
| 7909 case Token::SHL: __ shl_cl(eax); break; | |
| 7910 case Token::SHR: __ shr_cl(eax); break; | |
| 7911 default: UNREACHABLE(); | |
| 7912 } | |
| 7913 if (op_ == Token::SHR) { | |
| 7914 // Check if result is non-negative and fits in a smi. | |
| 7915 __ test(eax, Immediate(0xc0000000)); | |
| 7916 __ j(not_zero, &call_runtime); | |
| 7917 } else { | |
| 7918 // Check if result fits in a smi. | |
| 7919 __ cmp(eax, 0xc0000000); | |
| 7920 __ j(negative, &non_smi_result); | |
| 7921 } | |
| 7922 // Tag smi result and return. | |
| 7923 __ SmiTag(eax); | |
| 7924 GenerateReturn(masm); | |
| 7925 | |
| 7926 // All ops except SHR return a signed int32 that we load in a HeapNumber. | |
| 7927 if (op_ != Token::SHR) { | |
| 7928 __ bind(&non_smi_result); | |
| 7929 // Allocate a heap number if needed. | |
| 7930 __ mov(ebx, Operand(eax)); // ebx: result | |
| 7931 Label skip_allocation; | |
| 7932 switch (mode_) { | |
| 7933 case OVERWRITE_LEFT: | |
| 7934 case OVERWRITE_RIGHT: | |
| 7935 // If the operand was an object, we skip the | |
| 7936 // allocation of a heap number. | |
| 7937 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? | |
| 7938 1 * kPointerSize : 2 * kPointerSize)); | |
| 7939 __ test(eax, Immediate(kSmiTagMask)); | |
| 7940 __ j(not_zero, &skip_allocation, not_taken); | |
| 7941 // Fall through! | |
| 7942 case NO_OVERWRITE: | |
| 7943 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | |
| 7944 __ bind(&skip_allocation); | |
| 7945 break; | |
| 7946 default: UNREACHABLE(); | |
| 7947 } | |
| 7948 // Store the result in the HeapNumber and return. | |
| 7949 if (CpuFeatures::IsSupported(SSE2)) { | |
| 7950 CpuFeatures::Scope use_sse2(SSE2); | |
| 7951 __ cvtsi2sd(xmm0, Operand(ebx)); | |
| 7952 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | |
| 7953 } else { | |
| 7954 __ mov(Operand(esp, 1 * kPointerSize), ebx); | |
| 7955 __ fild_s(Operand(esp, 1 * kPointerSize)); | |
| 7956 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | |
| 7957 } | |
| 7958 GenerateReturn(masm); | |
| 7959 } | |
| 7960 break; | |
| 7961 } | |
| 7962 default: UNREACHABLE(); break; | |
| 7963 } | 8546 } |
| 7964 | 8547 |
| 7965 // If all else fails, use the runtime system to get the correct | 8548 // If all else fails, use the runtime system to get the correct |
| 7966 // result. If arguments was passed in registers now place them on the | 8549 // result. If arguments was passed in registers now place them on the |
| 7967 // stack in the correct order below the return address. | 8550 // stack in the correct order below the return address. |
| 7968 __ bind(&call_runtime); | 8551 __ bind(&call_runtime); |
| 7969 if (HasArgsInRegisters()) { | 8552 if (HasArgsInRegisters()) { |
| 7970 __ pop(ecx); | 8553 GenerateRegisterArgsPush(masm); |
| 7971 if (HasArgsReversed()) { | |
| 7972 __ push(eax); | |
| 7973 __ push(edx); | |
| 7974 } else { | |
| 7975 __ push(edx); | |
| 7976 __ push(eax); | |
| 7977 } | |
| 7978 __ push(ecx); | |
| 7979 } | 8554 } |
| 8555 |
| 7980 switch (op_) { | 8556 switch (op_) { |
| 7981 case Token::ADD: { | 8557 case Token::ADD: { |
| 7982 // Test for string arguments before calling runtime. | 8558 // Test for string arguments before calling runtime. |
| 7983 Label not_strings, not_string1, string1, string1_smi2; | 8559 Label not_strings, not_string1, string1, string1_smi2; |
| 7984 Result answer; | 8560 |
| 7985 __ test(edx, Immediate(kSmiTagMask)); | 8561 // If this stub has already generated FP-specific code then the arguments |
| 8562 // are already in edx, eax |
| 8563 if (!ShouldGenerateFPCode() && !HasArgsInRegisters()) { |
| 8564 GenerateLoadArguments(masm); |
| 8565 } |
| 8566 |
| 8567 // Registers containing left and right operands respectively. |
| 8568 Register lhs, rhs; |
| 8569 if (HasArgsReversed()) { |
| 8570 lhs = eax; |
| 8571 rhs = edx; |
| 8572 } else { |
| 8573 lhs = edx; |
| 8574 rhs = eax; |
| 8575 } |
| 8576 |
| 8577 // Test if first argument is a string. |
| 8578 __ test(lhs, Immediate(kSmiTagMask)); |
| 7986 __ j(zero, ¬_string1); | 8579 __ j(zero, ¬_string1); |
| 7987 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx); | 8580 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, ecx); |
| 7988 __ j(above_equal, ¬_string1); | 8581 __ j(above_equal, ¬_string1); |
| 7989 | 8582 |
| 7990 // First argument is a string, test second. | 8583 // First argument is a string, test second. |
| 7991 __ test(eax, Immediate(kSmiTagMask)); | 8584 __ test(rhs, Immediate(kSmiTagMask)); |
| 7992 __ j(zero, &string1_smi2); | 8585 __ j(zero, &string1_smi2); |
| 7993 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | 8586 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx); |
| 7994 __ j(above_equal, &string1); | 8587 __ j(above_equal, &string1); |
| 7995 | 8588 |
| 7996 // First and second argument are strings. Jump to the string add stub. | 8589 // First and second argument are strings. Jump to the string add stub. |
| 7997 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); | 8590 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); |
| 7998 __ TailCallStub(&string_add_stub); | 8591 __ TailCallStub(&string_add_stub); |
| 7999 | 8592 |
| 8000 __ bind(&string1_smi2); | 8593 __ bind(&string1_smi2); |
| 8001 // First argument is a string, second is a smi. Try to lookup the number | 8594 // First argument is a string, second is a smi. Try to lookup the number |
| 8002 // string for the smi in the number string cache. | 8595 // string for the smi in the number string cache. |
| 8003 NumberToStringStub::GenerateLookupNumberStringCache( | 8596 NumberToStringStub::GenerateLookupNumberStringCache( |
| 8004 masm, eax, edi, ebx, ecx, true, &string1); | 8597 masm, rhs, edi, ebx, ecx, true, &string1); |
| 8005 | 8598 |
| 8006 // Call the string add stub to make the result. | 8599 // Replace second argument on stack and tailcall string add stub to make |
| 8007 __ EnterInternalFrame(); | 8600 // the result. |
| 8008 __ push(edx); // Original first argument. | 8601 __ mov(Operand(esp, 1 * kPointerSize), edi); |
| 8009 __ push(edi); // Number to string result for second argument. | 8602 __ TailCallStub(&string_add_stub); |
| 8010 __ CallStub(&string_add_stub); | |
| 8011 __ LeaveInternalFrame(); | |
| 8012 __ ret(2 * kPointerSize); | |
| 8013 | 8603 |
| 8604 // Only first argument is a string. |
| 8014 __ bind(&string1); | 8605 __ bind(&string1); |
| 8015 __ InvokeBuiltin( | 8606 __ InvokeBuiltin(Builtins::STRING_ADD_LEFT, JUMP_FUNCTION); |
| 8016 HasArgsReversed() ? | |
| 8017 Builtins::STRING_ADD_RIGHT : | |
| 8018 Builtins::STRING_ADD_LEFT, | |
| 8019 JUMP_FUNCTION); | |
| 8020 | 8607 |
| 8021 // First argument was not a string, test second. | 8608 // First argument was not a string, test second. |
| 8022 __ bind(¬_string1); | 8609 __ bind(¬_string1); |
| 8023 __ test(eax, Immediate(kSmiTagMask)); | 8610 __ test(rhs, Immediate(kSmiTagMask)); |
| 8024 __ j(zero, ¬_strings); | 8611 __ j(zero, ¬_strings); |
| 8025 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); | 8612 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx); |
| 8026 __ j(above_equal, ¬_strings); | 8613 __ j(above_equal, ¬_strings); |
| 8027 | 8614 |
| 8028 // Only second argument is a string. | 8615 // Only second argument is a string. |
| 8029 __ InvokeBuiltin( | 8616 __ InvokeBuiltin(Builtins::STRING_ADD_RIGHT, JUMP_FUNCTION); |
| 8030 HasArgsReversed() ? | |
| 8031 Builtins::STRING_ADD_LEFT : | |
| 8032 Builtins::STRING_ADD_RIGHT, | |
| 8033 JUMP_FUNCTION); | |
| 8034 | 8617 |
| 8035 __ bind(¬_strings); | 8618 __ bind(¬_strings); |
| 8036 // Neither argument is a string. | 8619 // Neither argument is a string. |
| 8037 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); | 8620 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); |
| 8038 break; | 8621 break; |
| 8039 } | 8622 } |
| 8040 case Token::SUB: | 8623 case Token::SUB: |
| 8041 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); | 8624 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); |
| 8042 break; | 8625 break; |
| 8043 case Token::MUL: | 8626 case Token::MUL: |
| (...skipping 19 matching lines...) Expand all Loading... |
| 8063 break; | 8646 break; |
| 8064 case Token::SHL: | 8647 case Token::SHL: |
| 8065 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); | 8648 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); |
| 8066 break; | 8649 break; |
| 8067 case Token::SHR: | 8650 case Token::SHR: |
| 8068 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); | 8651 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); |
| 8069 break; | 8652 break; |
| 8070 default: | 8653 default: |
| 8071 UNREACHABLE(); | 8654 UNREACHABLE(); |
| 8072 } | 8655 } |
| 8656 |
| 8657 // Generate an unreachable reference to the DEFAULT stub so that it can be |
| 8658 // found at the end of this stub when clearing ICs at GC. |
| 8659 if (runtime_operands_type_ != BinaryOpIC::DEFAULT) { |
| 8660 GenericBinaryOpStub uninit(MinorKey(), BinaryOpIC::DEFAULT); |
| 8661 __ TailCallStub(&uninit); |
| 8662 } |
| 8073 } | 8663 } |
| 8074 | 8664 |
| 8075 | 8665 |
| 8076 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, | 8666 void GenericBinaryOpStub::GenerateHeapResultAllocation(MacroAssembler* masm, |
| 8077 Label* alloc_failure) { | 8667 Label* alloc_failure) { |
| 8078 Label skip_allocation; | 8668 Label skip_allocation; |
| 8079 OverwriteMode mode = mode_; | 8669 OverwriteMode mode = mode_; |
| 8080 if (HasArgsReversed()) { | 8670 if (HasArgsReversed()) { |
| 8081 if (mode == OVERWRITE_RIGHT) { | 8671 if (mode == OVERWRITE_RIGHT) { |
| 8082 mode = OVERWRITE_LEFT; | 8672 mode = OVERWRITE_LEFT; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8116 __ mov(eax, ebx); | 8706 __ mov(eax, ebx); |
| 8117 __ bind(&skip_allocation); | 8707 __ bind(&skip_allocation); |
| 8118 break; | 8708 break; |
| 8119 default: UNREACHABLE(); | 8709 default: UNREACHABLE(); |
| 8120 } | 8710 } |
| 8121 } | 8711 } |
| 8122 | 8712 |
| 8123 | 8713 |
| 8124 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { | 8714 void GenericBinaryOpStub::GenerateLoadArguments(MacroAssembler* masm) { |
| 8125 // If arguments are not passed in registers read them from the stack. | 8715 // If arguments are not passed in registers read them from the stack. |
| 8126 if (!HasArgsInRegisters()) { | 8716 ASSERT(!HasArgsInRegisters()); |
| 8127 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 8717 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 8128 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 8718 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 8129 } | |
| 8130 } | 8719 } |
| 8131 | 8720 |
| 8132 | 8721 |
| 8133 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { | 8722 void GenericBinaryOpStub::GenerateReturn(MacroAssembler* masm) { |
| 8134 // If arguments are not passed in registers remove them from the stack before | 8723 // If arguments are not passed in registers remove them from the stack before |
| 8135 // returning. | 8724 // returning. |
| 8136 if (!HasArgsInRegisters()) { | 8725 if (!HasArgsInRegisters()) { |
| 8137 __ ret(2 * kPointerSize); // Remove both operands | 8726 __ ret(2 * kPointerSize); // Remove both operands |
| 8138 } else { | 8727 } else { |
| 8139 __ ret(0); | 8728 __ ret(0); |
| 8140 } | 8729 } |
| 8141 } | 8730 } |
| 8142 | 8731 |
| 8143 | 8732 |
| 8733 void GenericBinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { |
| 8734 ASSERT(HasArgsInRegisters()); |
| 8735 __ pop(ecx); |
| 8736 if (HasArgsReversed()) { |
| 8737 __ push(eax); |
| 8738 __ push(edx); |
| 8739 } else { |
| 8740 __ push(edx); |
| 8741 __ push(eax); |
| 8742 } |
| 8743 __ push(ecx); |
| 8744 } |
| 8745 |
| 8746 |
| 8747 void GenericBinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 8748 Label get_result; |
| 8749 |
| 8750 // Keep a copy of operands on the stack and make sure they are also in |
| 8751 // edx, eax. |
| 8752 if (HasArgsInRegisters()) { |
| 8753 GenerateRegisterArgsPush(masm); |
| 8754 } else { |
| 8755 GenerateLoadArguments(masm); |
| 8756 } |
| 8757 |
| 8758 // Internal frame is necessary to handle exceptions properly. |
| 8759 __ EnterInternalFrame(); |
| 8760 |
| 8761 // Push arguments on stack if the stub expects them there. |
| 8762 if (!HasArgsInRegisters()) { |
| 8763 __ push(edx); |
| 8764 __ push(eax); |
| 8765 } |
| 8766 // Call the stub proper to get the result in eax. |
| 8767 __ call(&get_result); |
| 8768 __ LeaveInternalFrame(); |
| 8769 |
| 8770 __ pop(ecx); // Return address. |
| 8771 // Left and right arguments are now on top. |
| 8772 // Push the operation result. The tail call to BinaryOp_Patch will |
| 8773 // return it to the original caller. |
| 8774 __ push(eax); |
| 8775 // Push this stub's key. Although the operation and the type info are |
| 8776 // encoded into the key, the encoding is opaque, so push them too. |
| 8777 __ push(Immediate(Smi::FromInt(MinorKey()))); |
| 8778 __ push(Immediate(Smi::FromInt(op_))); |
| 8779 __ push(Immediate(Smi::FromInt(runtime_operands_type_))); |
| 8780 |
| 8781 __ push(ecx); // Return address. |
| 8782 |
| 8783 // Patch the caller to an appropriate specialized stub |
| 8784 // and return the operation result. |
| 8785 __ TailCallExternalReference( |
| 8786 ExternalReference(IC_Utility(IC::kBinaryOp_Patch)), |
| 8787 6, |
| 8788 1); |
| 8789 |
| 8790 // The entry point for the result calculation is assumed to be immediately |
| 8791 // after this sequence. |
| 8792 __ bind(&get_result); |
| 8793 } |
| 8794 |
| 8795 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
| 8796 GenericBinaryOpStub stub(key, type_info); |
| 8797 HandleScope scope; |
| 8798 return stub.GetCode(); |
| 8799 } |
| 8800 |
| 8801 |
| 8144 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | 8802 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 8145 // Input on stack: | 8803 // Input on stack: |
| 8146 // esp[4]: argument (should be number). | 8804 // esp[4]: argument (should be number). |
| 8147 // esp[0]: return address. | 8805 // esp[0]: return address. |
| 8148 // Test that eax is a number. | 8806 // Test that eax is a number. |
| 8149 Label runtime_call; | 8807 Label runtime_call; |
| 8150 Label runtime_call_clear_stack; | 8808 Label runtime_call_clear_stack; |
| 8151 Label input_not_smi; | 8809 Label input_not_smi; |
| 8152 Label loaded; | 8810 Label loaded; |
| 8153 __ mov(eax, Operand(esp, kPointerSize)); | 8811 __ mov(eax, Operand(esp, kPointerSize)); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8240 GenerateOperation(masm); | 8898 GenerateOperation(masm); |
| 8241 __ mov(Operand(ecx, 0), ebx); | 8899 __ mov(Operand(ecx, 0), ebx); |
| 8242 __ mov(Operand(ecx, kIntSize), edx); | 8900 __ mov(Operand(ecx, kIntSize), edx); |
| 8243 __ mov(Operand(ecx, 2 * kIntSize), eax); | 8901 __ mov(Operand(ecx, 2 * kIntSize), eax); |
| 8244 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 8902 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 8245 __ ret(kPointerSize); | 8903 __ ret(kPointerSize); |
| 8246 | 8904 |
| 8247 __ bind(&runtime_call_clear_stack); | 8905 __ bind(&runtime_call_clear_stack); |
| 8248 __ fstp(0); | 8906 __ fstp(0); |
| 8249 __ bind(&runtime_call); | 8907 __ bind(&runtime_call); |
| 8250 __ TailCallRuntime(ExternalReference(RuntimeFunction()), 1, 1); | 8908 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| 8251 } | 8909 } |
| 8252 | 8910 |
| 8253 | 8911 |
| 8254 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | 8912 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
| 8255 switch (type_) { | 8913 switch (type_) { |
| 8256 // Add more cases when necessary. | 8914 // Add more cases when necessary. |
| 8257 case TranscendentalCache::SIN: return Runtime::kMath_sin; | 8915 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
| 8258 case TranscendentalCache::COS: return Runtime::kMath_cos; | 8916 case TranscendentalCache::COS: return Runtime::kMath_cos; |
| 8259 default: | 8917 default: |
| 8260 UNIMPLEMENTED(); | 8918 UNIMPLEMENTED(); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8346 __ bind(&done); | 9004 __ bind(&done); |
| 8347 } | 9005 } |
| 8348 | 9006 |
| 8349 | 9007 |
| 8350 // Get the integer part of a heap number. Surprisingly, all this bit twiddling | 9008 // Get the integer part of a heap number. Surprisingly, all this bit twiddling |
| 8351 // is faster than using the built-in instructions on floating point registers. | 9009 // is faster than using the built-in instructions on floating point registers. |
| 8352 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the | 9010 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the |
| 8353 // trashed registers. | 9011 // trashed registers. |
| 8354 void IntegerConvert(MacroAssembler* masm, | 9012 void IntegerConvert(MacroAssembler* masm, |
| 8355 Register source, | 9013 Register source, |
| 9014 NumberInfo number_info, |
| 8356 bool use_sse3, | 9015 bool use_sse3, |
| 8357 Label* conversion_failure) { | 9016 Label* conversion_failure) { |
| 8358 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); | 9017 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); |
| 8359 Label done, right_exponent, normal_exponent; | 9018 Label done, right_exponent, normal_exponent; |
| 8360 Register scratch = ebx; | 9019 Register scratch = ebx; |
| 8361 Register scratch2 = edi; | 9020 Register scratch2 = edi; |
| 8362 // Get exponent word. | 9021 if (!number_info.IsInteger32() || !use_sse3) { |
| 8363 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 9022 // Get exponent word. |
| 8364 // Get exponent alone in scratch2. | 9023 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); |
| 8365 __ mov(scratch2, scratch); | 9024 // Get exponent alone in scratch2. |
| 8366 __ and_(scratch2, HeapNumber::kExponentMask); | 9025 __ mov(scratch2, scratch); |
| 9026 __ and_(scratch2, HeapNumber::kExponentMask); |
| 9027 } |
| 8367 if (use_sse3) { | 9028 if (use_sse3) { |
| 8368 CpuFeatures::Scope scope(SSE3); | 9029 CpuFeatures::Scope scope(SSE3); |
| 8369 // Check whether the exponent is too big for a 64 bit signed integer. | 9030 if (!number_info.IsInteger32()) { |
| 8370 static const uint32_t kTooBigExponent = | 9031 // Check whether the exponent is too big for a 64 bit signed integer. |
| 8371 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; | 9032 static const uint32_t kTooBigExponent = |
| 8372 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); | 9033 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; |
| 8373 __ j(greater_equal, conversion_failure); | 9034 __ cmp(Operand(scratch2), Immediate(kTooBigExponent)); |
| 9035 __ j(greater_equal, conversion_failure); |
| 9036 } |
| 8374 // Load x87 register with heap number. | 9037 // Load x87 register with heap number. |
| 8375 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); | 9038 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); |
| 8376 // Reserve space for 64 bit answer. | 9039 // Reserve space for 64 bit answer. |
| 8377 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. | 9040 __ sub(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. |
| 8378 // Do conversion, which cannot fail because we checked the exponent. | 9041 // Do conversion, which cannot fail because we checked the exponent. |
| 8379 __ fisttp_d(Operand(esp, 0)); | 9042 __ fisttp_d(Operand(esp, 0)); |
| 8380 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. | 9043 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. |
| 8381 __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. | 9044 __ add(Operand(esp), Immediate(sizeof(uint64_t))); // Nolint. |
| 8382 } else { | 9045 } else { |
| 8383 // Load ecx with zero. We use this either for the final shift or | 9046 // Load ecx with zero. We use this either for the final shift or |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8477 __ jmp(&done); | 9140 __ jmp(&done); |
| 8478 __ bind(&negative); | 9141 __ bind(&negative); |
| 8479 __ sub(ecx, Operand(scratch2)); | 9142 __ sub(ecx, Operand(scratch2)); |
| 8480 __ bind(&done); | 9143 __ bind(&done); |
| 8481 } | 9144 } |
| 8482 } | 9145 } |
| 8483 | 9146 |
| 8484 | 9147 |
| 8485 // Input: edx, eax are the left and right objects of a bit op. | 9148 // Input: edx, eax are the left and right objects of a bit op. |
| 8486 // Output: eax, ecx are left and right integers for a bit op. | 9149 // Output: eax, ecx are left and right integers for a bit op. |
| 8487 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, | 9150 void FloatingPointHelper::LoadNumbersAsIntegers(MacroAssembler* masm, |
| 8488 bool use_sse3, | 9151 NumberInfo number_info, |
| 8489 Label* conversion_failure) { | 9152 bool use_sse3, |
| 9153 Label* conversion_failure) { |
| 8490 // Check float operands. | 9154 // Check float operands. |
| 8491 Label arg1_is_object, check_undefined_arg1; | 9155 Label arg1_is_object, check_undefined_arg1; |
| 8492 Label arg2_is_object, check_undefined_arg2; | 9156 Label arg2_is_object, check_undefined_arg2; |
| 8493 Label load_arg2, done; | 9157 Label load_arg2, done; |
| 8494 | 9158 |
| 9159 if (!number_info.IsHeapNumber()) { |
| 9160 if (!number_info.IsSmi()) { |
| 9161 __ test(edx, Immediate(kSmiTagMask)); |
| 9162 __ j(not_zero, &arg1_is_object); |
| 9163 } |
| 9164 __ SmiUntag(edx); |
| 9165 __ jmp(&load_arg2); |
| 9166 } |
| 9167 |
| 9168 __ bind(&arg1_is_object); |
| 9169 |
| 9170 // Get the untagged integer version of the edx heap number in ecx. |
| 9171 IntegerConvert(masm, edx, number_info, use_sse3, conversion_failure); |
| 9172 __ mov(edx, ecx); |
| 9173 |
| 9174 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 9175 __ bind(&load_arg2); |
| 9176 if (!number_info.IsHeapNumber()) { |
| 9177 // Test if arg2 is a Smi. |
| 9178 if (!number_info.IsSmi()) { |
| 9179 __ test(eax, Immediate(kSmiTagMask)); |
| 9180 __ j(not_zero, &arg2_is_object); |
| 9181 } |
| 9182 __ SmiUntag(eax); |
| 9183 __ mov(ecx, eax); |
| 9184 __ jmp(&done); |
| 9185 } |
| 9186 |
| 9187 __ bind(&arg2_is_object); |
| 9188 |
| 9189 // Get the untagged integer version of the eax heap number in ecx. |
| 9190 IntegerConvert(masm, eax, number_info, use_sse3, conversion_failure); |
| 9191 __ bind(&done); |
| 9192 __ mov(eax, edx); |
| 9193 } |
| 9194 |
| 9195 |
| 9196 // Input: edx, eax are the left and right objects of a bit op. |
| 9197 // Output: eax, ecx are left and right integers for a bit op. |
| 9198 void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, |
| 9199 bool use_sse3, |
| 9200 Label* conversion_failure) { |
| 9201 // Check float operands. |
| 9202 Label arg1_is_object, check_undefined_arg1; |
| 9203 Label arg2_is_object, check_undefined_arg2; |
| 9204 Label load_arg2, done; |
| 9205 |
| 9206 // Test if arg1 is a Smi. |
| 8495 __ test(edx, Immediate(kSmiTagMask)); | 9207 __ test(edx, Immediate(kSmiTagMask)); |
| 8496 __ j(not_zero, &arg1_is_object); | 9208 __ j(not_zero, &arg1_is_object); |
| 9209 |
| 8497 __ SmiUntag(edx); | 9210 __ SmiUntag(edx); |
| 8498 __ jmp(&load_arg2); | 9211 __ jmp(&load_arg2); |
| 8499 | 9212 |
| 8500 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 9213 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
| 8501 __ bind(&check_undefined_arg1); | 9214 __ bind(&check_undefined_arg1); |
| 8502 __ cmp(edx, Factory::undefined_value()); | 9215 __ cmp(edx, Factory::undefined_value()); |
| 8503 __ j(not_equal, conversion_failure); | 9216 __ j(not_equal, conversion_failure); |
| 8504 __ mov(edx, Immediate(0)); | 9217 __ mov(edx, Immediate(0)); |
| 8505 __ jmp(&load_arg2); | 9218 __ jmp(&load_arg2); |
| 8506 | 9219 |
| 8507 __ bind(&arg1_is_object); | 9220 __ bind(&arg1_is_object); |
| 8508 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 9221 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 8509 __ cmp(ebx, Factory::heap_number_map()); | 9222 __ cmp(ebx, Factory::heap_number_map()); |
| 8510 __ j(not_equal, &check_undefined_arg1); | 9223 __ j(not_equal, &check_undefined_arg1); |
| 9224 |
| 8511 // Get the untagged integer version of the edx heap number in ecx. | 9225 // Get the untagged integer version of the edx heap number in ecx. |
| 8512 IntegerConvert(masm, edx, use_sse3, conversion_failure); | 9226 IntegerConvert(masm, |
| 9227 edx, |
| 9228 NumberInfo::Unknown(), |
| 9229 use_sse3, |
| 9230 conversion_failure); |
| 8513 __ mov(edx, ecx); | 9231 __ mov(edx, ecx); |
| 8514 | 9232 |
| 8515 // Here edx has the untagged integer, eax has a Smi or a heap number. | 9233 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 8516 __ bind(&load_arg2); | 9234 __ bind(&load_arg2); |
| 9235 |
| 8517 // Test if arg2 is a Smi. | 9236 // Test if arg2 is a Smi. |
| 8518 __ test(eax, Immediate(kSmiTagMask)); | 9237 __ test(eax, Immediate(kSmiTagMask)); |
| 8519 __ j(not_zero, &arg2_is_object); | 9238 __ j(not_zero, &arg2_is_object); |
| 9239 |
| 8520 __ SmiUntag(eax); | 9240 __ SmiUntag(eax); |
| 8521 __ mov(ecx, eax); | 9241 __ mov(ecx, eax); |
| 8522 __ jmp(&done); | 9242 __ jmp(&done); |
| 8523 | 9243 |
| 8524 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 9244 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
| 8525 __ bind(&check_undefined_arg2); | 9245 __ bind(&check_undefined_arg2); |
| 8526 __ cmp(eax, Factory::undefined_value()); | 9246 __ cmp(eax, Factory::undefined_value()); |
| 8527 __ j(not_equal, conversion_failure); | 9247 __ j(not_equal, conversion_failure); |
| 8528 __ mov(ecx, Immediate(0)); | 9248 __ mov(ecx, Immediate(0)); |
| 8529 __ jmp(&done); | 9249 __ jmp(&done); |
| 8530 | 9250 |
| 8531 __ bind(&arg2_is_object); | 9251 __ bind(&arg2_is_object); |
| 8532 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 9252 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 8533 __ cmp(ebx, Factory::heap_number_map()); | 9253 __ cmp(ebx, Factory::heap_number_map()); |
| 8534 __ j(not_equal, &check_undefined_arg2); | 9254 __ j(not_equal, &check_undefined_arg2); |
| 9255 |
| 8535 // Get the untagged integer version of the eax heap number in ecx. | 9256 // Get the untagged integer version of the eax heap number in ecx. |
| 8536 IntegerConvert(masm, eax, use_sse3, conversion_failure); | 9257 IntegerConvert(masm, |
| 9258 eax, |
| 9259 NumberInfo::Unknown(), |
| 9260 use_sse3, |
| 9261 conversion_failure); |
| 8537 __ bind(&done); | 9262 __ bind(&done); |
| 8538 __ mov(eax, edx); | 9263 __ mov(eax, edx); |
| 8539 } | 9264 } |
| 8540 | 9265 |
| 8541 | 9266 |
| 9267 void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm, |
| 9268 NumberInfo number_info, |
| 9269 bool use_sse3, |
| 9270 Label* conversion_failure) { |
| 9271 if (number_info.IsNumber()) { |
| 9272 LoadNumbersAsIntegers(masm, number_info, use_sse3, conversion_failure); |
| 9273 } else { |
| 9274 LoadUnknownsAsIntegers(masm, use_sse3, conversion_failure); |
| 9275 } |
| 9276 } |
| 9277 |
| 9278 |
| 8542 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, | 9279 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, |
| 8543 Register number) { | 9280 Register number) { |
| 8544 Label load_smi, done; | 9281 Label load_smi, done; |
| 8545 | 9282 |
| 8546 __ test(number, Immediate(kSmiTagMask)); | 9283 __ test(number, Immediate(kSmiTagMask)); |
| 8547 __ j(zero, &load_smi, not_taken); | 9284 __ j(zero, &load_smi, not_taken); |
| 8548 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); | 9285 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); |
| 8549 __ jmp(&done); | 9286 __ jmp(&done); |
| 8550 | 9287 |
| 8551 __ bind(&load_smi); | 9288 __ bind(&load_smi); |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8768 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); | 9505 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); |
| 8769 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); | 9506 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); |
| 8770 } | 9507 } |
| 8771 } else if (op_ == Token::BIT_NOT) { | 9508 } else if (op_ == Token::BIT_NOT) { |
| 8772 // Check if the operand is a heap number. | 9509 // Check if the operand is a heap number. |
| 8773 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 9510 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 8774 __ cmp(edx, Factory::heap_number_map()); | 9511 __ cmp(edx, Factory::heap_number_map()); |
| 8775 __ j(not_equal, &slow, not_taken); | 9512 __ j(not_equal, &slow, not_taken); |
| 8776 | 9513 |
| 8777 // Convert the heap number in eax to an untagged integer in ecx. | 9514 // Convert the heap number in eax to an untagged integer in ecx. |
| 8778 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), &slow); | 9515 IntegerConvert(masm, |
| 9516 eax, |
| 9517 NumberInfo::Unknown(), |
| 9518 CpuFeatures::IsSupported(SSE3), |
| 9519 &slow); |
| 8779 | 9520 |
| 8780 // Do the bitwise operation and check if the result fits in a smi. | 9521 // Do the bitwise operation and check if the result fits in a smi. |
| 8781 Label try_float; | 9522 Label try_float; |
| 8782 __ not_(ecx); | 9523 __ not_(ecx); |
| 8783 __ cmp(ecx, 0xc0000000); | 9524 __ cmp(ecx, 0xc0000000); |
| 8784 __ j(sign, &try_float, not_taken); | 9525 __ j(sign, &try_float, not_taken); |
| 8785 | 9526 |
| 8786 // Tag the result as a smi and we're done. | 9527 // Tag the result as a smi and we're done. |
| 8787 ASSERT(kSmiTagSize == 1); | 9528 ASSERT(kSmiTagSize == 1); |
| 8788 __ lea(eax, Operand(ecx, times_2, kSmiTag)); | 9529 __ lea(eax, Operand(ecx, times_2, kSmiTag)); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8904 __ neg(edx); | 9645 __ neg(edx); |
| 8905 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); | 9646 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); |
| 8906 __ ret(0); | 9647 __ ret(0); |
| 8907 | 9648 |
| 8908 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 9649 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 8909 // by calling the runtime system. | 9650 // by calling the runtime system. |
| 8910 __ bind(&slow); | 9651 __ bind(&slow); |
| 8911 __ pop(ebx); // Return address. | 9652 __ pop(ebx); // Return address. |
| 8912 __ push(edx); | 9653 __ push(edx); |
| 8913 __ push(ebx); | 9654 __ push(ebx); |
| 8914 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1, 1); | 9655 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 8915 } | 9656 } |
| 8916 | 9657 |
| 8917 | 9658 |
| 8918 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 9659 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { |
| 8919 // esp[0] : return address | 9660 // esp[0] : return address |
| 8920 // esp[4] : number of parameters | 9661 // esp[4] : number of parameters |
| 8921 // esp[8] : receiver displacement | 9662 // esp[8] : receiver displacement |
| 8922 // esp[16] : function | 9663 // esp[16] : function |
| 8923 | 9664 |
| 8924 // The displacement is used for skipping the return address and the | 9665 // The displacement is used for skipping the return address and the |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9005 __ sub(Operand(edx), Immediate(kPointerSize)); | 9746 __ sub(Operand(edx), Immediate(kPointerSize)); |
| 9006 __ dec(ecx); | 9747 __ dec(ecx); |
| 9007 __ j(not_zero, &loop); | 9748 __ j(not_zero, &loop); |
| 9008 | 9749 |
| 9009 // Return and remove the on-stack parameters. | 9750 // Return and remove the on-stack parameters. |
| 9010 __ bind(&done); | 9751 __ bind(&done); |
| 9011 __ ret(3 * kPointerSize); | 9752 __ ret(3 * kPointerSize); |
| 9012 | 9753 |
| 9013 // Do the runtime call to allocate the arguments object. | 9754 // Do the runtime call to allocate the arguments object. |
| 9014 __ bind(&runtime); | 9755 __ bind(&runtime); |
| 9015 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3, 1); | 9756 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 9016 } | 9757 } |
| 9017 | 9758 |
| 9018 | 9759 |
| 9019 void RegExpExecStub::Generate(MacroAssembler* masm) { | 9760 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 9020 // Just jump directly to runtime if native RegExp is not selected at compile | 9761 // Just jump directly to runtime if native RegExp is not selected at compile |
| 9021 // time or if regexp entry in generated code is turned off runtime switch or | 9762 // time or if regexp entry in generated code is turned off runtime switch or |
| 9022 // at compilation. | 9763 // at compilation. |
| 9023 #ifndef V8_NATIVE_REGEXP | 9764 #ifndef V8_NATIVE_REGEXP |
| 9024 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); | 9765 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 9025 #else // V8_NATIVE_REGEXP | 9766 #else // V8_NATIVE_REGEXP |
| 9026 if (!FLAG_regexp_entry_native) { | 9767 if (!FLAG_regexp_entry_native) { |
| 9027 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); | 9768 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 9028 return; | 9769 return; |
| 9029 } | 9770 } |
| 9030 | 9771 |
| 9031 // Stack frame on entry. | 9772 // Stack frame on entry. |
| 9032 // esp[0]: return address | 9773 // esp[0]: return address |
| 9033 // esp[4]: last_match_info (expected JSArray) | 9774 // esp[4]: last_match_info (expected JSArray) |
| 9034 // esp[8]: previous index | 9775 // esp[8]: previous index |
| 9035 // esp[12]: subject string | 9776 // esp[12]: subject string |
| 9036 // esp[16]: JSRegExp object | 9777 // esp[16]: JSRegExp object |
| 9037 | 9778 |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9200 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | 9941 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); |
| 9201 __ SmiUntag(ebx); // Previous index from smi. | 9942 __ SmiUntag(ebx); // Previous index from smi. |
| 9202 | 9943 |
| 9203 // eax: subject string | 9944 // eax: subject string |
| 9204 // ebx: previous index | 9945 // ebx: previous index |
| 9205 // edx: code | 9946 // edx: code |
| 9206 // edi: encoding of subject string (1 if ascii 0 if two_byte); | 9947 // edi: encoding of subject string (1 if ascii 0 if two_byte); |
| 9207 // All checks done. Now push arguments for native regexp code. | 9948 // All checks done. Now push arguments for native regexp code. |
| 9208 __ IncrementCounter(&Counters::regexp_entry_native, 1); | 9949 __ IncrementCounter(&Counters::regexp_entry_native, 1); |
| 9209 | 9950 |
| 9951 static const int kRegExpExecuteArguments = 7; |
| 9952 __ PrepareCallCFunction(kRegExpExecuteArguments, ecx); |
| 9953 |
| 9210 // Argument 7: Indicate that this is a direct call from JavaScript. | 9954 // Argument 7: Indicate that this is a direct call from JavaScript. |
| 9211 __ push(Immediate(1)); | 9955 __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); |
| 9212 | 9956 |
| 9213 // Argument 6: Start (high end) of backtracking stack memory area. | 9957 // Argument 6: Start (high end) of backtracking stack memory area. |
| 9214 __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); | 9958 __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); |
| 9215 __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 9959 __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
| 9216 __ push(ecx); | 9960 __ mov(Operand(esp, 5 * kPointerSize), ecx); |
| 9217 | 9961 |
| 9218 // Argument 5: static offsets vector buffer. | 9962 // Argument 5: static offsets vector buffer. |
| 9219 __ push(Immediate(ExternalReference::address_of_static_offsets_vector())); | 9963 __ mov(Operand(esp, 4 * kPointerSize), |
| 9964 Immediate(ExternalReference::address_of_static_offsets_vector())); |
| 9220 | 9965 |
| 9221 // Argument 4: End of string data | 9966 // Argument 4: End of string data |
| 9222 // Argument 3: Start of string data | 9967 // Argument 3: Start of string data |
| 9223 Label push_two_byte, push_rest; | 9968 Label setup_two_byte, setup_rest; |
| 9224 __ test(edi, Operand(edi)); | 9969 __ test(edi, Operand(edi)); |
| 9225 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); | 9970 __ mov(edi, FieldOperand(eax, String::kLengthOffset)); |
| 9226 __ j(zero, &push_two_byte); | 9971 __ j(zero, &setup_two_byte); |
| 9227 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); | 9972 __ lea(ecx, FieldOperand(eax, edi, times_1, SeqAsciiString::kHeaderSize)); |
| 9228 __ push(ecx); // Argument 4. | 9973 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
| 9229 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); | 9974 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); |
| 9230 __ push(ecx); // Argument 3. | 9975 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
| 9231 __ jmp(&push_rest); | 9976 __ jmp(&setup_rest); |
| 9232 | 9977 |
| 9233 __ bind(&push_two_byte); | 9978 __ bind(&setup_two_byte); |
| 9234 __ lea(ecx, FieldOperand(eax, edi, times_2, SeqTwoByteString::kHeaderSize)); | 9979 __ lea(ecx, FieldOperand(eax, edi, times_2, SeqTwoByteString::kHeaderSize)); |
| 9235 __ push(ecx); // Argument 4. | 9980 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. |
| 9236 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); | 9981 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); |
| 9237 __ push(ecx); // Argument 3. | 9982 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. |
| 9238 | 9983 |
| 9239 __ bind(&push_rest); | 9984 __ bind(&setup_rest); |
| 9240 | 9985 |
| 9241 // Argument 2: Previous index. | 9986 // Argument 2: Previous index. |
| 9242 __ push(ebx); | 9987 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 9243 | 9988 |
| 9244 // Argument 1: Subject string. | 9989 // Argument 1: Subject string. |
| 9245 __ push(eax); | 9990 __ mov(Operand(esp, 0 * kPointerSize), eax); |
| 9246 | 9991 |
| 9247 // Locate the code entry and call it. | 9992 // Locate the code entry and call it. |
| 9248 __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); | 9993 __ add(Operand(edx), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 9249 __ call(Operand(edx)); | 9994 __ CallCFunction(edx, kRegExpExecuteArguments); |
| 9250 // Remove arguments. | |
| 9251 __ add(Operand(esp), Immediate(7 * kPointerSize)); | |
| 9252 | 9995 |
| 9253 // Check the result. | 9996 // Check the result. |
| 9254 Label success; | 9997 Label success; |
| 9255 __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); | 9998 __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); |
| 9256 __ j(equal, &success, taken); | 9999 __ j(equal, &success, taken); |
| 9257 Label failure; | 10000 Label failure; |
| 9258 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); | 10001 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); |
| 9259 __ j(equal, &failure, taken); | 10002 __ j(equal, &failure, taken); |
| 9260 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); | 10003 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); |
| 9261 // If not exception it can only be retry. Handle that in the runtime system. | 10004 // If not exception it can only be retry. Handle that in the runtime system. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9339 edi); | 10082 edi); |
| 9340 __ jmp(&next_capture); | 10083 __ jmp(&next_capture); |
| 9341 __ bind(&done); | 10084 __ bind(&done); |
| 9342 | 10085 |
| 9343 // Return last match info. | 10086 // Return last match info. |
| 9344 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 10087 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |
| 9345 __ ret(4 * kPointerSize); | 10088 __ ret(4 * kPointerSize); |
| 9346 | 10089 |
| 9347 // Do the runtime call to execute the regexp. | 10090 // Do the runtime call to execute the regexp. |
| 9348 __ bind(&runtime); | 10091 __ bind(&runtime); |
| 9349 __ TailCallRuntime(ExternalReference(Runtime::kRegExpExec), 4, 1); | 10092 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 9350 #endif // V8_NATIVE_REGEXP | 10093 #endif // V8_NATIVE_REGEXP |
| 9351 } | 10094 } |
| 9352 | 10095 |
| 9353 | 10096 |
| 9354 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, | 10097 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, |
| 9355 Register object, | 10098 Register object, |
| 9356 Register result, | 10099 Register result, |
| 9357 Register scratch1, | 10100 Register scratch1, |
| 9358 Register scratch2, | 10101 Register scratch2, |
| 9359 bool object_is_smi, | 10102 bool object_is_smi, |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9408 Label runtime; | 10151 Label runtime; |
| 9409 | 10152 |
| 9410 __ mov(ebx, Operand(esp, kPointerSize)); | 10153 __ mov(ebx, Operand(esp, kPointerSize)); |
| 9411 | 10154 |
| 9412 // Generate code to lookup number in the number string cache. | 10155 // Generate code to lookup number in the number string cache. |
| 9413 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); | 10156 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); |
| 9414 __ ret(1 * kPointerSize); | 10157 __ ret(1 * kPointerSize); |
| 9415 | 10158 |
| 9416 __ bind(&runtime); | 10159 __ bind(&runtime); |
| 9417 // Handle number to string in the runtime system if not found in the cache. | 10160 // Handle number to string in the runtime system if not found in the cache. |
| 9418 __ TailCallRuntime(ExternalReference(Runtime::kNumberToString), 1, 1); | 10161 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); |
| 9419 } | 10162 } |
| 9420 | 10163 |
| 9421 | 10164 |
| 9422 void CompareStub::Generate(MacroAssembler* masm) { | 10165 void CompareStub::Generate(MacroAssembler* masm) { |
| 9423 Label call_builtin, done; | 10166 Label call_builtin, done; |
| 9424 | 10167 |
| 9425 // NOTICE! This code is only reached after a smi-fast-case check, so | 10168 // NOTICE! This code is only reached after a smi-fast-case check, so |
| 9426 // it is certain that at least one operand isn't a smi. | 10169 // it is certain that at least one operand isn't a smi. |
| 9427 | 10170 |
| 9428 if (cc_ == equal) { // Both strict and non-strict. | 10171 if (cc_ == equal) { // Both strict and non-strict. |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9693 void StackCheckStub::Generate(MacroAssembler* masm) { | 10436 void StackCheckStub::Generate(MacroAssembler* masm) { |
| 9694 // Because builtins always remove the receiver from the stack, we | 10437 // Because builtins always remove the receiver from the stack, we |
| 9695 // have to fake one to avoid underflowing the stack. The receiver | 10438 // have to fake one to avoid underflowing the stack. The receiver |
| 9696 // must be inserted below the return address on the stack so we | 10439 // must be inserted below the return address on the stack so we |
| 9697 // temporarily store that in a register. | 10440 // temporarily store that in a register. |
| 9698 __ pop(eax); | 10441 __ pop(eax); |
| 9699 __ push(Immediate(Smi::FromInt(0))); | 10442 __ push(Immediate(Smi::FromInt(0))); |
| 9700 __ push(eax); | 10443 __ push(eax); |
| 9701 | 10444 |
| 9702 // Do tail-call to runtime routine. | 10445 // Do tail-call to runtime routine. |
| 9703 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1, 1); | 10446 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); |
| 9704 } | 10447 } |
| 9705 | 10448 |
| 9706 | 10449 |
| 9707 void CallFunctionStub::Generate(MacroAssembler* masm) { | 10450 void CallFunctionStub::Generate(MacroAssembler* masm) { |
| 9708 Label slow; | 10451 Label slow; |
| 9709 | 10452 |
| 9710 // If the receiver might be a value (string, number or boolean) check for this | 10453 // If the receiver might be a value (string, number or boolean) check for this |
| 9711 // and box it if it is. | 10454 // and box it if it is. |
| 9712 if (ReceiverMightBeValue()) { | 10455 if (ReceiverMightBeValue()) { |
| 9713 // Get the receiver from the stack. | 10456 // Get the receiver from the stack. |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9854 // It was zero; the result is undefined. | 10597 // It was zero; the result is undefined. |
| 9855 __ mov(eax, Factory::undefined_value()); | 10598 __ mov(eax, Factory::undefined_value()); |
| 9856 __ jmp(&prologue); | 10599 __ jmp(&prologue); |
| 9857 // It was non-zero. Dereference to get the result value. | 10600 // It was non-zero. Dereference to get the result value. |
| 9858 __ bind(&get_result); | 10601 __ bind(&get_result); |
| 9859 __ mov(eax, Operand(eax, 0)); | 10602 __ mov(eax, Operand(eax, 0)); |
| 9860 __ bind(&prologue); | 10603 __ bind(&prologue); |
| 9861 __ LeaveExitFrame(ExitFrame::MODE_NORMAL); | 10604 __ LeaveExitFrame(ExitFrame::MODE_NORMAL); |
| 9862 __ ret(0); | 10605 __ ret(0); |
| 9863 __ bind(&promote_scheduled_exception); | 10606 __ bind(&promote_scheduled_exception); |
| 9864 __ TailCallRuntime(ExternalReference(Runtime::kPromoteScheduledException), | 10607 __ TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); |
| 9865 0, | |
| 9866 1); | |
| 9867 } | 10608 } |
| 9868 | 10609 |
| 9869 | 10610 |
| 9870 void CEntryStub::GenerateCore(MacroAssembler* masm, | 10611 void CEntryStub::GenerateCore(MacroAssembler* masm, |
| 9871 Label* throw_normal_exception, | 10612 Label* throw_normal_exception, |
| 9872 Label* throw_termination_exception, | 10613 Label* throw_termination_exception, |
| 9873 Label* throw_out_of_memory_exception, | 10614 Label* throw_out_of_memory_exception, |
| 9874 bool do_gc, | 10615 bool do_gc, |
| 9875 bool always_allocate_scope) { | 10616 bool always_allocate_scope) { |
| 9876 // eax: result parameter for PerformGC, if any | 10617 // eax: result parameter for PerformGC, if any |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10341 | 11082 |
| 10342 // Get the two characters forming the sub string. | 11083 // Get the two characters forming the sub string. |
| 10343 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 11084 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
| 10344 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 11085 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
| 10345 | 11086 |
| 10346 // Try to lookup two character string in symbol table. If it is not found | 11087 // Try to lookup two character string in symbol table. If it is not found |
| 10347 // just allocate a new one. | 11088 // just allocate a new one. |
| 10348 Label make_two_character_string, make_flat_ascii_string; | 11089 Label make_two_character_string, make_flat_ascii_string; |
| 10349 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, | 11090 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, |
| 10350 &make_two_character_string); | 11091 &make_two_character_string); |
| 11092 __ IncrementCounter(&Counters::string_add_native, 1); |
| 10351 __ ret(2 * kPointerSize); | 11093 __ ret(2 * kPointerSize); |
| 10352 | 11094 |
| 10353 __ bind(&make_two_character_string); | 11095 __ bind(&make_two_character_string); |
| 10354 __ Set(ebx, Immediate(2)); | 11096 __ Set(ebx, Immediate(2)); |
| 10355 __ jmp(&make_flat_ascii_string); | 11097 __ jmp(&make_flat_ascii_string); |
| 10356 | 11098 |
| 10357 __ bind(&longer_than_two); | 11099 __ bind(&longer_than_two); |
| 10358 // Check if resulting string will be flat. | 11100 // Check if resulting string will be flat. |
| 10359 __ cmp(ebx, String::kMinNonFlatLength); | 11101 __ cmp(ebx, String::kMinNonFlatLength); |
| 10360 __ j(below, &string_add_flat_result); | 11102 __ j(below, &string_add_flat_result); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10485 // eax: result string | 11227 // eax: result string |
| 10486 // ecx: next character of result | 11228 // ecx: next character of result |
| 10487 // edx: first char of second argument | 11229 // edx: first char of second argument |
| 10488 // edi: length of second argument | 11230 // edi: length of second argument |
| 10489 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 11231 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
| 10490 __ IncrementCounter(&Counters::string_add_native, 1); | 11232 __ IncrementCounter(&Counters::string_add_native, 1); |
| 10491 __ ret(2 * kPointerSize); | 11233 __ ret(2 * kPointerSize); |
| 10492 | 11234 |
| 10493 // Just jump to runtime to add the two strings. | 11235 // Just jump to runtime to add the two strings. |
| 10494 __ bind(&string_add_runtime); | 11236 __ bind(&string_add_runtime); |
| 10495 __ TailCallRuntime(ExternalReference(Runtime::kStringAdd), 2, 1); | 11237 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 10496 } | 11238 } |
| 10497 | 11239 |
| 10498 | 11240 |
| 10499 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, | 11241 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, |
| 10500 Register dest, | 11242 Register dest, |
| 10501 Register src, | 11243 Register src, |
| 10502 Register count, | 11244 Register count, |
| 10503 Register scratch, | 11245 Register scratch, |
| 10504 bool ascii) { | 11246 bool ascii) { |
| 10505 Label loop; | 11247 Label loop; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10549 } | 11291 } |
| 10550 | 11292 |
| 10551 // Don't enter the rep movs if there are less than 4 bytes to copy. | 11293 // Don't enter the rep movs if there are less than 4 bytes to copy. |
| 10552 Label last_bytes; | 11294 Label last_bytes; |
| 10553 __ test(count, Immediate(~3)); | 11295 __ test(count, Immediate(~3)); |
| 10554 __ j(zero, &last_bytes); | 11296 __ j(zero, &last_bytes); |
| 10555 | 11297 |
| 10556 // Copy from edi to esi using rep movs instruction. | 11298 // Copy from edi to esi using rep movs instruction. |
| 10557 __ mov(scratch, count); | 11299 __ mov(scratch, count); |
| 10558 __ sar(count, 2); // Number of doublewords to copy. | 11300 __ sar(count, 2); // Number of doublewords to copy. |
| 11301 __ cld(); |
| 10559 __ rep_movs(); | 11302 __ rep_movs(); |
| 10560 | 11303 |
| 10561 // Find number of bytes left. | 11304 // Find number of bytes left. |
| 10562 __ mov(count, scratch); | 11305 __ mov(count, scratch); |
| 10563 __ and_(count, 3); | 11306 __ and_(count, 3); |
| 10564 | 11307 |
| 10565 // Check if there are more bytes to copy. | 11308 // Check if there are more bytes to copy. |
| 10566 __ bind(&last_bytes); | 11309 __ bind(&last_bytes); |
| 10567 __ test(count, Operand(count)); | 11310 __ test(count, Operand(count)); |
| 10568 __ j(zero, &done); | 11311 __ j(zero, &done); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10620 | 11363 |
| 10621 // Load the symbol table. | 11364 // Load the symbol table. |
| 10622 Register symbol_table = c2; | 11365 Register symbol_table = c2; |
| 10623 ExternalReference roots_address = ExternalReference::roots_address(); | 11366 ExternalReference roots_address = ExternalReference::roots_address(); |
| 10624 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); | 11367 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); |
| 10625 __ mov(symbol_table, | 11368 __ mov(symbol_table, |
| 10626 Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 11369 Operand::StaticArray(scratch, times_pointer_size, roots_address)); |
| 10627 | 11370 |
| 10628 // Calculate capacity mask from the symbol table capacity. | 11371 // Calculate capacity mask from the symbol table capacity. |
| 10629 Register mask = scratch2; | 11372 Register mask = scratch2; |
| 10630 static const int kCapacityOffset = | 11373 __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); |
| 10631 FixedArray::kHeaderSize + | |
| 10632 SymbolTable::kCapacityIndex * kPointerSize; | |
| 10633 __ mov(mask, FieldOperand(symbol_table, kCapacityOffset)); | |
| 10634 __ SmiUntag(mask); | 11374 __ SmiUntag(mask); |
| 10635 __ sub(Operand(mask), Immediate(1)); | 11375 __ sub(Operand(mask), Immediate(1)); |
| 10636 | 11376 |
| 10637 // Registers | 11377 // Registers |
| 10638 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | 11378 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 10639 // hash: hash of two character string | 11379 // hash: hash of two character string |
| 10640 // symbol_table: symbol table | 11380 // symbol_table: symbol table |
| 10641 // mask: capacity mask | 11381 // mask: capacity mask |
| 10642 // scratch: - | 11382 // scratch: - |
| 10643 | 11383 |
| 10644 // Perform a number of probes in the symbol table. | 11384 // Perform a number of probes in the symbol table. |
| 10645 static const int kProbes = 4; | 11385 static const int kProbes = 4; |
| 10646 Label found_in_symbol_table; | 11386 Label found_in_symbol_table; |
| 10647 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; | 11387 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; |
| 10648 for (int i = 0; i < kProbes; i++) { | 11388 for (int i = 0; i < kProbes; i++) { |
| 10649 // Calculate entry in symbol table. | 11389 // Calculate entry in symbol table. |
| 10650 __ mov(scratch, hash); | 11390 __ mov(scratch, hash); |
| 10651 if (i > 0) { | 11391 if (i > 0) { |
| 10652 __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); | 11392 __ add(Operand(scratch), Immediate(SymbolTable::GetProbeOffset(i))); |
| 10653 } | 11393 } |
| 10654 __ and_(scratch, Operand(mask)); | 11394 __ and_(scratch, Operand(mask)); |
| 10655 | 11395 |
| 10656 // Load the entry from the symble table. | 11396 // Load the entry from the symble table. |
| 10657 Register candidate = scratch; // Scratch register contains candidate. | 11397 Register candidate = scratch; // Scratch register contains candidate. |
| 10658 ASSERT_EQ(1, SymbolTableShape::kEntrySize); | 11398 ASSERT_EQ(1, SymbolTable::kEntrySize); |
| 10659 static const int kFirstElementOffset = | |
| 10660 FixedArray::kHeaderSize + | |
| 10661 SymbolTable::kPrefixStartIndex * kPointerSize + | |
| 10662 SymbolTableShape::kPrefixSize * kPointerSize; | |
| 10663 __ mov(candidate, | 11399 __ mov(candidate, |
| 10664 FieldOperand(symbol_table, | 11400 FieldOperand(symbol_table, |
| 10665 scratch, | 11401 scratch, |
| 10666 times_pointer_size, | 11402 times_pointer_size, |
| 10667 kFirstElementOffset)); | 11403 SymbolTable::kElementsStartOffset)); |
| 10668 | 11404 |
| 10669 // If entry is undefined no string with this hash can be found. | 11405 // If entry is undefined no string with this hash can be found. |
| 10670 __ cmp(candidate, Factory::undefined_value()); | 11406 __ cmp(candidate, Factory::undefined_value()); |
| 10671 __ j(equal, not_found); | 11407 __ j(equal, not_found); |
| 10672 | 11408 |
| 10673 // If length is not 2 the string is not a candidate. | 11409 // If length is not 2 the string is not a candidate. |
| 10674 __ cmp(FieldOperand(candidate, String::kLengthOffset), Immediate(2)); | 11410 __ cmp(FieldOperand(candidate, String::kLengthOffset), Immediate(2)); |
| 10675 __ j(not_equal, &next_probe[i]); | 11411 __ j(not_equal, &next_probe[i]); |
| 10676 | 11412 |
| 10677 // As we are out of registers save the mask on the stack and use that | 11413 // As we are out of registers save the mask on the stack and use that |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10811 // Get the two characters forming the sub string. | 11547 // Get the two characters forming the sub string. |
| 10812 __ SmiUntag(edx); // From index is no longer smi. | 11548 __ SmiUntag(edx); // From index is no longer smi. |
| 10813 __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize)); | 11549 __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize)); |
| 10814 __ movzx_b(ecx, | 11550 __ movzx_b(ecx, |
| 10815 FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1)); | 11551 FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1)); |
| 10816 | 11552 |
| 10817 // Try to lookup two character string in symbol table. | 11553 // Try to lookup two character string in symbol table. |
| 10818 Label make_two_character_string; | 11554 Label make_two_character_string; |
| 10819 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, | 11555 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, |
| 10820 &make_two_character_string); | 11556 &make_two_character_string); |
| 10821 __ ret(2 * kPointerSize); | 11557 __ ret(3 * kPointerSize); |
| 10822 | 11558 |
| 10823 __ bind(&make_two_character_string); | 11559 __ bind(&make_two_character_string); |
| 10824 // Setup registers for allocating the two character string. | 11560 // Setup registers for allocating the two character string. |
| 10825 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 11561 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 10826 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 11562 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 10827 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 11563 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 10828 __ Set(ecx, Immediate(2)); | 11564 __ Set(ecx, Immediate(2)); |
| 10829 | 11565 |
| 10830 __ bind(&result_longer_than_two); | 11566 __ bind(&result_longer_than_two); |
| 10831 // eax: string | 11567 // eax: string |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10895 // edx: original value of esi | 11631 // edx: original value of esi |
| 10896 // edi: first character of result | 11632 // edi: first character of result |
| 10897 // esi: character of sub string start | 11633 // esi: character of sub string start |
| 10898 GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); | 11634 GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |
| 10899 __ mov(esi, edx); // Restore esi. | 11635 __ mov(esi, edx); // Restore esi. |
| 10900 __ IncrementCounter(&Counters::sub_string_native, 1); | 11636 __ IncrementCounter(&Counters::sub_string_native, 1); |
| 10901 __ ret(3 * kPointerSize); | 11637 __ ret(3 * kPointerSize); |
| 10902 | 11638 |
| 10903 // Just jump to runtime to create the sub string. | 11639 // Just jump to runtime to create the sub string. |
| 10904 __ bind(&runtime); | 11640 __ bind(&runtime); |
| 10905 __ TailCallRuntime(ExternalReference(Runtime::kSubString), 3, 1); | 11641 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 10906 } | 11642 } |
| 10907 | 11643 |
| 10908 | 11644 |
| 10909 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 11645 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 10910 Register left, | 11646 Register left, |
| 10911 Register right, | 11647 Register right, |
| 10912 Register scratch1, | 11648 Register scratch1, |
| 10913 Register scratch2, | 11649 Register scratch2, |
| 10914 Register scratch3) { | 11650 Register scratch3) { |
| 10915 Label result_not_equal; | 11651 Label result_not_equal; |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11011 // Check that both objects are sequential ascii strings. | 11747 // Check that both objects are sequential ascii strings. |
| 11012 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 11748 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
| 11013 | 11749 |
| 11014 // Compare flat ascii strings. | 11750 // Compare flat ascii strings. |
| 11015 __ IncrementCounter(&Counters::string_compare_native, 1); | 11751 __ IncrementCounter(&Counters::string_compare_native, 1); |
| 11016 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 11752 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
| 11017 | 11753 |
| 11018 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 11754 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 11019 // tagged as a small integer. | 11755 // tagged as a small integer. |
| 11020 __ bind(&runtime); | 11756 __ bind(&runtime); |
| 11021 __ TailCallRuntime(ExternalReference(Runtime::kStringCompare), 2, 1); | 11757 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 11022 } | 11758 } |
| 11023 | 11759 |
| 11024 #undef __ | 11760 #undef __ |
| 11025 | 11761 |
| 11026 } } // namespace v8::internal | 11762 } } // namespace v8::internal |
| OLD | NEW |