Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: src/ia32/codegen-ia32.cc

Issue 844006: Merge changes up to V8 version 2.1.3 into the partial snapshots (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/ia32/debug-ia32.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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_ = &register_allocator; 135 allocator_ = &register_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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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, &not_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(&not_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
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
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
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
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
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
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
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
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
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
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(&not_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, &not_string1); 8579 __ j(zero, &not_string1);
7987 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ecx); 8580 __ CmpObjectType(lhs, FIRST_NONSTRING_TYPE, ecx);
7988 __ j(above_equal, &not_string1); 8581 __ j(above_equal, &not_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(&not_string1); 8609 __ bind(&not_string1);
8023 __ test(eax, Immediate(kSmiTagMask)); 8610 __ test(rhs, Immediate(kSmiTagMask));
8024 __ j(zero, &not_strings); 8611 __ j(zero, &not_strings);
8025 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx); 8612 __ CmpObjectType(rhs, FIRST_NONSTRING_TYPE, ecx);
8026 __ j(above_equal, &not_strings); 8613 __ j(above_equal, &not_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(&not_strings); 8618 __ bind(&not_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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.h ('k') | src/ia32/debug-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698