OLD | NEW |
---|---|
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 void ICRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { | 102 void ICRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
103 masm->LeaveInternalFrame(); | 103 masm->LeaveInternalFrame(); |
104 } | 104 } |
105 | 105 |
106 | 106 |
107 // ------------------------------------------------------------------------- | 107 // ------------------------------------------------------------------------- |
108 // CodeGenState implementation. | 108 // CodeGenState implementation. |
109 | 109 |
110 CodeGenState::CodeGenState(CodeGenerator* owner) | 110 CodeGenState::CodeGenState(CodeGenerator* owner) |
111 : owner_(owner), | 111 : owner_(owner), |
112 true_target_(NULL), | 112 previous_(owner->state()) { |
113 false_target_(NULL), | 113 owner->set_state(this); |
114 previous_(NULL) { | |
115 owner_->set_state(this); | |
116 } | 114 } |
117 | 115 |
118 | 116 |
119 CodeGenState::CodeGenState(CodeGenerator* owner, | 117 ConditionCodeGenState::ConditionCodeGenState(CodeGenerator* owner, |
120 JumpTarget* true_target, | 118 JumpTarget* true_target, |
121 JumpTarget* false_target) | 119 JumpTarget* false_target) |
122 : owner_(owner), | 120 : CodeGenState(owner), |
123 true_target_(true_target), | 121 true_target_(true_target), |
124 false_target_(false_target), | 122 false_target_(false_target) { |
125 previous_(owner->state()) { | 123 owner->set_state(this); |
126 owner_->set_state(this); | 124 } |
125 | |
126 | |
127 TypeInfoCodeGenState::TypeInfoCodeGenState(CodeGenerator* owner, | |
128 Slot* slot, | |
129 TypeInfo type_info) | |
130 : CodeGenState(owner), | |
131 slot_(slot) { | |
132 owner->set_state(this); | |
133 old_type_info_ = owner->set_type_info(slot, type_info); | |
127 } | 134 } |
128 | 135 |
129 | 136 |
130 CodeGenState::~CodeGenState() { | 137 CodeGenState::~CodeGenState() { |
131 ASSERT(owner_->state() == this); | 138 ASSERT(owner_->state() == this); |
132 owner_->set_state(previous_); | 139 owner_->set_state(previous_); |
133 } | 140 } |
134 | 141 |
135 | 142 |
143 TypeInfoCodeGenState::~TypeInfoCodeGenState() { | |
144 owner()->set_type_info(slot_, old_type_info_); | |
145 } | |
146 | |
136 // ------------------------------------------------------------------------- | 147 // ------------------------------------------------------------------------- |
137 // CodeGenerator implementation | 148 // CodeGenerator implementation |
138 | 149 |
139 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 150 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
140 : deferred_(8), | 151 : deferred_(8), |
141 masm_(masm), | 152 masm_(masm), |
142 info_(NULL), | 153 info_(NULL), |
143 frame_(NULL), | 154 frame_(NULL), |
144 allocator_(NULL), | 155 allocator_(NULL), |
145 cc_reg_(al), | 156 cc_reg_(al), |
146 state_(NULL), | 157 state_(NULL), |
147 loop_nesting_(0), | 158 loop_nesting_(0), |
159 type_info_(NULL), | |
148 function_return_is_shadowed_(false) { | 160 function_return_is_shadowed_(false) { |
149 } | 161 } |
150 | 162 |
151 | 163 |
152 // Calling conventions: | 164 // Calling conventions: |
153 // fp: caller's frame pointer | 165 // fp: caller's frame pointer |
154 // sp: stack pointer | 166 // sp: stack pointer |
155 // r1: called JS function | 167 // r1: called JS function |
156 // cp: callee's context | 168 // cp: callee's context |
157 | 169 |
158 void CodeGenerator::Generate(CompilationInfo* info) { | 170 void CodeGenerator::Generate(CompilationInfo* info) { |
159 // Record the position for debugging purposes. | 171 // Record the position for debugging purposes. |
160 CodeForFunctionPosition(info->function()); | 172 CodeForFunctionPosition(info->function()); |
161 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); | 173 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); |
162 | 174 |
163 // Initialize state. | 175 // Initialize state. |
164 info_ = info; | 176 info_ = info; |
177 | |
178 int slots = scope()->num_parameters() + scope()->num_stack_slots(); | |
179 ScopedVector<TypeInfo> type_info_array(slots); | |
180 type_info_ = &type_info_array; | |
181 | |
165 ASSERT(allocator_ == NULL); | 182 ASSERT(allocator_ == NULL); |
166 RegisterAllocator register_allocator(this); | 183 RegisterAllocator register_allocator(this); |
167 allocator_ = ®ister_allocator; | 184 allocator_ = ®ister_allocator; |
168 ASSERT(frame_ == NULL); | 185 ASSERT(frame_ == NULL); |
169 frame_ = new VirtualFrame(); | 186 frame_ = new VirtualFrame(); |
170 cc_reg_ = al; | 187 cc_reg_ = al; |
171 | 188 |
172 // Adjust for function-level loop nesting. | 189 // Adjust for function-level loop nesting. |
173 ASSERT_EQ(0, loop_nesting_); | 190 ASSERT_EQ(0, loop_nesting_); |
174 loop_nesting_ = info->loop_nesting(); | 191 loop_nesting_ = info->loop_nesting(); |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 ASSERT(!function_return_is_shadowed_); | 403 ASSERT(!function_return_is_shadowed_); |
387 function_return_.Unuse(); | 404 function_return_.Unuse(); |
388 DeleteFrame(); | 405 DeleteFrame(); |
389 | 406 |
390 // Process any deferred code using the register allocator. | 407 // Process any deferred code using the register allocator. |
391 if (!HasStackOverflow()) { | 408 if (!HasStackOverflow()) { |
392 ProcessDeferred(); | 409 ProcessDeferred(); |
393 } | 410 } |
394 | 411 |
395 allocator_ = NULL; | 412 allocator_ = NULL; |
413 type_info_ = NULL; | |
414 } | |
415 | |
416 | |
417 int CodeGenerator::NumberOfSlot(Slot* slot) { | |
418 if (slot == NULL) return kInvalidSlotNumber; | |
419 switch(slot->type()) { | |
420 case Slot::PARAMETER: | |
421 return slot->index(); | |
422 case Slot::LOCAL: | |
423 return slot->index() + scope()->num_parameters(); | |
424 default: | |
425 break; | |
426 } | |
427 return kInvalidSlotNumber; | |
396 } | 428 } |
397 | 429 |
398 | 430 |
399 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 431 MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
400 // Currently, this assertion will fail if we try to assign to | 432 // Currently, this assertion will fail if we try to assign to |
401 // a constant variable that is constant because it is read-only | 433 // a constant variable that is constant because it is read-only |
402 // (such as the variable referring to a named function expression). | 434 // (such as the variable referring to a named function expression). |
403 // We need to implement assignments to read-only variables. | 435 // We need to implement assignments to read-only variables. |
404 // Ideally, we should do this during AST generation (by converting | 436 // Ideally, we should do this during AST generation (by converting |
405 // such assignments into expression statements); however, in general | 437 // such assignments into expression statements); however, in general |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 // condition code register and no value is pushed. If the condition code | 515 // condition code register and no value is pushed. If the condition code |
484 // register was set, has_cc() is true and cc_reg_ contains the condition to | 516 // register was set, has_cc() is true and cc_reg_ contains the condition to |
485 // test for 'true'. | 517 // test for 'true'. |
486 void CodeGenerator::LoadCondition(Expression* x, | 518 void CodeGenerator::LoadCondition(Expression* x, |
487 JumpTarget* true_target, | 519 JumpTarget* true_target, |
488 JumpTarget* false_target, | 520 JumpTarget* false_target, |
489 bool force_cc) { | 521 bool force_cc) { |
490 ASSERT(!has_cc()); | 522 ASSERT(!has_cc()); |
491 int original_height = frame_->height(); | 523 int original_height = frame_->height(); |
492 | 524 |
493 { CodeGenState new_state(this, true_target, false_target); | 525 { ConditionCodeGenState new_state(this, true_target, false_target); |
494 Visit(x); | 526 Visit(x); |
495 | 527 |
496 // If we hit a stack overflow, we may not have actually visited | 528 // If we hit a stack overflow, we may not have actually visited |
497 // the expression. In that case, we ensure that we have a | 529 // the expression. In that case, we ensure that we have a |
498 // valid-looking frame state because we will continue to generate | 530 // valid-looking frame state because we will continue to generate |
499 // code as we unwind the C++ stack. | 531 // code as we unwind the C++ stack. |
500 // | 532 // |
501 // It's possible to have both a stack overflow and a valid frame | 533 // It's possible to have both a stack overflow and a valid frame |
502 // state (eg, a subexpression overflowed, visiting it returned | 534 // state (eg, a subexpression overflowed, visiting it returned |
503 // with a dummied frame state, and visiting this expression | 535 // with a dummied frame state, and visiting this expression |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
782 frame_->EmitPush(r0); | 814 frame_->EmitPush(r0); |
783 frame_->CallRuntime(Runtime::kToBool, 1); | 815 frame_->CallRuntime(Runtime::kToBool, 1); |
784 // Convert the result (r0) to a condition code. | 816 // Convert the result (r0) to a condition code. |
785 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 817 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
786 __ cmp(r0, ip); | 818 __ cmp(r0, ip); |
787 | 819 |
788 cc_reg_ = ne; | 820 cc_reg_ = ne; |
789 } | 821 } |
790 | 822 |
791 | 823 |
792 void CodeGenerator::GenericBinaryOperation(Token::Value op, | |
793 OverwriteMode overwrite_mode, | |
794 int constant_rhs) { | |
795 VirtualFrame::SpilledScope spilled_scope(frame_); | |
796 // sp[0] : y | |
797 // sp[1] : x | |
798 // result : r0 | |
799 | |
800 // Stub is entered with a call: 'return address' is in lr. | |
801 switch (op) { | |
802 case Token::ADD: | |
803 case Token::SUB: | |
804 case Token::MUL: | |
805 case Token::DIV: | |
806 case Token::MOD: | |
807 case Token::BIT_OR: | |
808 case Token::BIT_AND: | |
809 case Token::BIT_XOR: | |
810 case Token::SHL: | |
811 case Token::SHR: | |
812 case Token::SAR: { | |
813 frame_->EmitPop(r0); // r0 : y | |
814 frame_->EmitPop(r1); // r1 : x | |
815 GenericBinaryOpStub stub(op, overwrite_mode, r1, r0, constant_rhs); | |
816 frame_->CallStub(&stub, 0); | |
817 break; | |
818 } | |
819 | |
820 case Token::COMMA: | |
821 frame_->EmitPop(r0); | |
822 // Simply discard left value. | |
823 frame_->Drop(); | |
824 break; | |
825 | |
826 default: | |
827 // Other cases should have been handled before this point. | |
828 UNREACHABLE(); | |
829 break; | |
830 } | |
831 } | |
832 | |
833 | |
834 void CodeGenerator::VirtualFrameBinaryOperation(Token::Value op, | 824 void CodeGenerator::VirtualFrameBinaryOperation(Token::Value op, |
Søren Thygesen Gjesse
2010/06/02 09:24:01
VirtualFrameBinaryOperation -> GenericBinaryOperat
| |
835 OverwriteMode overwrite_mode, | 825 OverwriteMode overwrite_mode, |
826 GenerateInlineSmi inline_smi, | |
836 int constant_rhs) { | 827 int constant_rhs) { |
837 // top of virtual frame: y | 828 // top of virtual frame: y |
838 // 2nd elt. on virtual frame : x | 829 // 2nd elt. on virtual frame : x |
839 // result : top of virtual frame | 830 // result : top of virtual frame |
840 | 831 |
841 // Stub is entered with a call: 'return address' is in lr. | 832 // Stub is entered with a call: 'return address' is in lr. |
842 switch (op) { | 833 switch (op) { |
843 case Token::ADD: // fall through. | 834 case Token::ADD: |
844 case Token::SUB: // fall through. | 835 case Token::SUB: |
836 if (inline_smi) { | |
837 JumpTarget done; | |
838 Register rhs = frame_->PopToRegister(); | |
839 Register lhs = frame_->PopToRegister(rhs); // Don't pop to rhs register . | |
840 Register scratch = VirtualFrame::scratch0(); | |
841 __ orr(scratch, rhs, Operand(lhs)); | |
842 // Check they are both small and positive. | |
843 __ tst(scratch, Operand(kSmiTagMask | 0xc0000000)); | |
844 ASSERT(rhs.is(r0) || lhs.is(r0)); // r0 is free now. | |
845 ASSERT_EQ(0, kSmiTag); | |
846 if (op == Token::ADD) { | |
847 __ add(r0, lhs, Operand(rhs), LeaveCC, eq); | |
848 } else { | |
849 __ sub(r0, lhs, Operand(rhs), LeaveCC, eq); | |
850 } | |
851 done.Branch(eq); | |
852 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); | |
853 frame_->SpillAll(); | |
854 frame_->CallStub(&stub, 0); | |
855 done.Bind(); | |
856 frame_->EmitPush(r0); | |
857 break; | |
858 } else { | |
859 // Fall through! | |
860 } | |
861 case Token::BIT_OR: | |
862 case Token::BIT_AND: | |
863 case Token::BIT_XOR: | |
864 if (inline_smi) { | |
865 bool rhs_is_smi = frame_->KnownSmiAt(0); | |
866 bool lhs_is_smi = frame_->KnownSmiAt(1); | |
867 Register rhs = frame_->PopToRegister(); | |
868 Register lhs = frame_->PopToRegister(rhs); // Don't pop to rhs register . | |
Søren Thygesen Gjesse
2010/06/02 09:24:01
Long line.
| |
869 Register smi_test_reg; | |
870 Condition cond; | |
871 if (!rhs_is_smi || !lhs_is_smi) { | |
872 if (!rhs_is_smi) { | |
873 smi_test_reg = rhs; | |
874 } else if (!lhs_is_smi) { | |
875 smi_test_reg = lhs; | |
876 } else { | |
877 smi_test_reg = VirtualFrame::scratch0(); | |
878 __ orr(smi_test_reg, rhs, Operand(lhs)); | |
879 } | |
880 // Check they are both Smis. | |
881 __ tst(smi_test_reg, Operand(kSmiTagMask)); | |
882 cond = eq; | |
883 } else { | |
884 cond = al; | |
885 } | |
886 ASSERT(rhs.is(r0) || lhs.is(r0)); // r0 is free now. | |
887 if (op == Token::BIT_OR) { | |
888 __ orr(r0, lhs, Operand(rhs), LeaveCC, cond); | |
889 } else if (op == Token::BIT_AND) { | |
890 __ and_(r0, lhs, Operand(rhs), LeaveCC, cond); | |
891 } else { | |
892 ASSERT(op == Token::BIT_XOR); | |
893 ASSERT_EQ(0, kSmiTag); | |
894 __ eor(r0, lhs, Operand(rhs), LeaveCC, cond); | |
895 } | |
896 if (cond != al) { | |
897 JumpTarget done; | |
898 done.Branch(cond); | |
899 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); | |
900 frame_->SpillAll(); | |
901 frame_->CallStub(&stub, 0); | |
902 done.Bind(); | |
903 } | |
904 frame_->EmitPush(r0); | |
905 break; | |
906 } else { | |
907 // Fall through! | |
908 } | |
845 case Token::MUL: | 909 case Token::MUL: |
846 case Token::DIV: | 910 case Token::DIV: |
847 case Token::MOD: | 911 case Token::MOD: |
848 case Token::BIT_OR: | |
849 case Token::BIT_AND: | |
850 case Token::BIT_XOR: | |
851 case Token::SHL: | 912 case Token::SHL: |
852 case Token::SHR: | 913 case Token::SHR: |
853 case Token::SAR: { | 914 case Token::SAR: { |
854 Register rhs = frame_->PopToRegister(); | 915 Register rhs = frame_->PopToRegister(); |
855 Register lhs = frame_->PopToRegister(rhs); // Don't pop to rhs register. | 916 Register lhs = frame_->PopToRegister(rhs); // Don't pop to rhs register. |
856 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); | 917 GenericBinaryOpStub stub(op, overwrite_mode, lhs, rhs, constant_rhs); |
857 frame_->SpillAll(); | 918 frame_->SpillAll(); |
858 frame_->CallStub(&stub, 0); | 919 frame_->CallStub(&stub, 0); |
859 frame_->EmitPush(r0); | 920 frame_->EmitPush(r0); |
860 break; | 921 break; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
965 if (!reversed_) { | 1026 if (!reversed_) { |
966 if (tos_register_.is(r1)) { | 1027 if (tos_register_.is(r1)) { |
967 __ mov(r0, Operand(Smi::FromInt(value_))); | 1028 __ mov(r0, Operand(Smi::FromInt(value_))); |
968 } else { | 1029 } else { |
969 ASSERT(tos_register_.is(r0)); | 1030 ASSERT(tos_register_.is(r0)); |
970 __ mov(r1, Operand(Smi::FromInt(value_))); | 1031 __ mov(r1, Operand(Smi::FromInt(value_))); |
971 lhs = r0; | 1032 lhs = r0; |
972 rhs = r1; | 1033 rhs = r1; |
973 } | 1034 } |
974 } else { | 1035 } else { |
975 UNREACHABLE(); // Should have been handled in SmiOperation. | 1036 ASSERT(op_ == Token::SHL); |
1037 __ mov(r1, Operand(Smi::FromInt(value_))); | |
976 } | 1038 } |
977 break; | 1039 break; |
978 } | 1040 } |
979 | 1041 |
980 default: | 1042 default: |
981 // Other cases should have been handled before this point. | 1043 // Other cases should have been handled before this point. |
982 UNREACHABLE(); | 1044 UNREACHABLE(); |
983 break; | 1045 break; |
984 } | 1046 } |
985 | 1047 |
(...skipping 27 matching lines...) Expand all Loading... | |
1013 return bit_posn; | 1075 return bit_posn; |
1014 } | 1076 } |
1015 | 1077 |
1016 | 1078 |
1017 void CodeGenerator::SmiOperation(Token::Value op, | 1079 void CodeGenerator::SmiOperation(Token::Value op, |
1018 Handle<Object> value, | 1080 Handle<Object> value, |
1019 bool reversed, | 1081 bool reversed, |
1020 OverwriteMode mode) { | 1082 OverwriteMode mode) { |
1021 int int_value = Smi::cast(*value)->value(); | 1083 int int_value = Smi::cast(*value)->value(); |
1022 | 1084 |
1085 bool both_sides_are_smi = frame_->KnownSmiAt(0); | |
1086 | |
1023 bool something_to_inline; | 1087 bool something_to_inline; |
1024 switch (op) { | 1088 switch (op) { |
1025 case Token::ADD: | 1089 case Token::ADD: |
1026 case Token::SUB: | 1090 case Token::SUB: |
1027 case Token::BIT_AND: | 1091 case Token::BIT_AND: |
1028 case Token::BIT_OR: | 1092 case Token::BIT_OR: |
1029 case Token::BIT_XOR: { | 1093 case Token::BIT_XOR: { |
1030 something_to_inline = true; | 1094 something_to_inline = true; |
1031 break; | 1095 break; |
1032 } | 1096 } |
1033 case Token::SHL: | 1097 case Token::SHL: { |
1098 something_to_inline = (both_sides_are_smi || !reversed); | |
1099 break; | |
1100 } | |
1034 case Token::SHR: | 1101 case Token::SHR: |
1035 case Token::SAR: { | 1102 case Token::SAR: { |
1036 if (reversed) { | 1103 if (reversed) { |
1037 something_to_inline = false; | 1104 something_to_inline = false; |
1038 } else { | 1105 } else { |
1039 something_to_inline = true; | 1106 something_to_inline = true; |
1040 } | 1107 } |
1041 break; | 1108 break; |
1042 } | 1109 } |
1043 case Token::MOD: { | 1110 case Token::MOD: { |
(...skipping 16 matching lines...) Expand all Loading... | |
1060 something_to_inline = false; | 1127 something_to_inline = false; |
1061 break; | 1128 break; |
1062 } | 1129 } |
1063 } | 1130 } |
1064 | 1131 |
1065 if (!something_to_inline) { | 1132 if (!something_to_inline) { |
1066 if (!reversed) { | 1133 if (!reversed) { |
1067 // Push the rhs onto the virtual frame by putting it in a TOS register. | 1134 // Push the rhs onto the virtual frame by putting it in a TOS register. |
1068 Register rhs = frame_->GetTOSRegister(); | 1135 Register rhs = frame_->GetTOSRegister(); |
1069 __ mov(rhs, Operand(value)); | 1136 __ mov(rhs, Operand(value)); |
1070 frame_->EmitPush(rhs); | 1137 frame_->EmitPush(rhs, TypeInfo::Smi()); |
1071 VirtualFrameBinaryOperation(op, mode, int_value); | 1138 VirtualFrameBinaryOperation(op, mode, GENERATE_INLINE_SMI, int_value); |
1072 } else { | 1139 } else { |
1073 // Pop the rhs, then push lhs and rhs in the right order. Only performs | 1140 // Pop the rhs, then push lhs and rhs in the right order. Only performs |
1074 // at most one pop, the rest takes place in TOS registers. | 1141 // at most one pop, the rest takes place in TOS registers. |
1075 Register lhs = frame_->GetTOSRegister(); // Get reg for pushing. | 1142 Register lhs = frame_->GetTOSRegister(); // Get reg for pushing. |
1076 Register rhs = frame_->PopToRegister(lhs); // Don't use lhs for this. | 1143 Register rhs = frame_->PopToRegister(lhs); // Don't use lhs for this. |
1077 __ mov(lhs, Operand(value)); | 1144 __ mov(lhs, Operand(value)); |
1078 frame_->EmitPush(lhs); | 1145 frame_->EmitPush(lhs, TypeInfo::Smi()); |
1079 frame_->EmitPush(rhs); | 1146 TypeInfo t = both_sides_are_smi ? TypeInfo::Smi() : TypeInfo::Unknown(); |
1080 VirtualFrameBinaryOperation(op, mode, kUnknownIntValue); | 1147 frame_->EmitPush(rhs, t); |
1148 VirtualFrameBinaryOperation(op, mode, GENERATE_INLINE_SMI, kUnknownIntValu e); | |
Søren Thygesen Gjesse
2010/06/02 09:24:01
Long line.
| |
1081 } | 1149 } |
1082 return; | 1150 return; |
1083 } | 1151 } |
1084 | 1152 |
1085 // We move the top of stack to a register (normally no move is invoved). | 1153 // We move the top of stack to a register (normally no move is invoved). |
1086 Register tos = frame_->PopToRegister(); | 1154 Register tos = frame_->PopToRegister(); |
1087 // All other registers are spilled. The deferred code expects one argument | 1155 // All other registers are spilled. The deferred code expects one argument |
1088 // in a register and all other values are flushed to the stack. The | 1156 // in a register and all other values are flushed to the stack. The |
1089 // answer is returned in the same register that the top of stack argument was | 1157 // answer is returned in the same register that the top of stack argument was |
1090 // in. | 1158 // in. |
1091 frame_->SpillAll(); | 1159 frame_->SpillAll(); |
1092 | 1160 |
1093 switch (op) { | 1161 switch (op) { |
1094 case Token::ADD: { | 1162 case Token::ADD: { |
1095 DeferredCode* deferred = | 1163 DeferredCode* deferred = |
1096 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 1164 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); |
1097 | 1165 |
1098 __ add(tos, tos, Operand(value), SetCC); | 1166 __ add(tos, tos, Operand(value), SetCC); |
1099 deferred->Branch(vs); | 1167 deferred->Branch(vs); |
1100 __ tst(tos, Operand(kSmiTagMask)); | 1168 if (!both_sides_are_smi) { |
1101 deferred->Branch(ne); | 1169 __ tst(tos, Operand(kSmiTagMask)); |
1170 deferred->Branch(ne); | |
1171 } | |
1102 deferred->BindExit(); | 1172 deferred->BindExit(); |
1103 frame_->EmitPush(tos); | 1173 frame_->EmitPush(tos); |
1104 break; | 1174 break; |
1105 } | 1175 } |
1106 | 1176 |
1107 case Token::SUB: { | 1177 case Token::SUB: { |
1108 DeferredCode* deferred = | 1178 DeferredCode* deferred = |
1109 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 1179 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); |
1110 | 1180 |
1111 if (reversed) { | 1181 if (reversed) { |
1112 __ rsb(tos, tos, Operand(value), SetCC); | 1182 __ rsb(tos, tos, Operand(value), SetCC); |
1113 } else { | 1183 } else { |
1114 __ sub(tos, tos, Operand(value), SetCC); | 1184 __ sub(tos, tos, Operand(value), SetCC); |
1115 } | 1185 } |
1116 deferred->Branch(vs); | 1186 deferred->Branch(vs); |
1117 __ tst(tos, Operand(kSmiTagMask)); | 1187 if (!both_sides_are_smi) { |
1118 deferred->Branch(ne); | 1188 __ tst(tos, Operand(kSmiTagMask)); |
1189 deferred->Branch(ne); | |
1190 } | |
1119 deferred->BindExit(); | 1191 deferred->BindExit(); |
1120 frame_->EmitPush(tos); | 1192 frame_->EmitPush(tos); |
1121 break; | 1193 break; |
1122 } | 1194 } |
1123 | 1195 |
1124 | 1196 |
1125 case Token::BIT_OR: | 1197 case Token::BIT_OR: |
1126 case Token::BIT_XOR: | 1198 case Token::BIT_XOR: |
1127 case Token::BIT_AND: { | 1199 case Token::BIT_AND: { |
1128 DeferredCode* deferred = | 1200 if (both_sides_are_smi) { |
1129 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 1201 switch (op) { |
1130 __ tst(tos, Operand(kSmiTagMask)); | 1202 case Token::BIT_OR: __ orr(tos, tos, Operand(value)); break; |
1131 deferred->Branch(ne); | 1203 case Token::BIT_XOR: __ eor(tos, tos, Operand(value)); break; |
1132 switch (op) { | 1204 case Token::BIT_AND: __ and_(tos, tos, Operand(value)); break; |
1133 case Token::BIT_OR: __ orr(tos, tos, Operand(value)); break; | 1205 default: UNREACHABLE(); |
1134 case Token::BIT_XOR: __ eor(tos, tos, Operand(value)); break; | 1206 } |
1135 case Token::BIT_AND: __ and_(tos, tos, Operand(value)); break; | 1207 frame_->EmitPush(tos, TypeInfo::Smi()); |
1136 default: UNREACHABLE(); | 1208 } else { |
1209 DeferredCode* deferred = | |
1210 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | |
1211 __ tst(tos, Operand(kSmiTagMask)); | |
1212 deferred->Branch(ne); | |
1213 switch (op) { | |
1214 case Token::BIT_OR: __ orr(tos, tos, Operand(value)); break; | |
1215 case Token::BIT_XOR: __ eor(tos, tos, Operand(value)); break; | |
1216 case Token::BIT_AND: __ and_(tos, tos, Operand(value)); break; | |
1217 default: UNREACHABLE(); | |
1218 } | |
1219 deferred->BindExit(); | |
1220 TypeInfo result_type = | |
1221 (op == Token::BIT_AND) ? TypeInfo::Smi() : TypeInfo::Integer32(); | |
1222 frame_->EmitPush(tos, result_type); | |
1137 } | 1223 } |
1138 deferred->BindExit(); | |
1139 frame_->EmitPush(tos); | |
1140 break; | 1224 break; |
1141 } | 1225 } |
1142 | 1226 |
1143 case Token::SHL: | 1227 case Token::SHL: |
1228 if (reversed) { | |
1229 ASSERT(both_sides_are_smi); | |
1230 int max_shift = 0; | |
1231 int max_result = int_value == 0 ? 1 : int_value; | |
1232 while (Smi::IsValid(max_result << 1)) { | |
1233 max_shift++; | |
1234 max_result <<= 1; | |
1235 } | |
1236 DeferredCode* deferred = | |
1237 new DeferredInlineSmiOperation(op, int_value, true, mode, tos); | |
1238 // Mask off the last 5 bits of the shift operand (rhs). This is part | |
1239 // of the definition of shift in JS and we know we have a Smi so we | |
1240 // can safely do this. The masked version gets passed to the | |
1241 // deferred code, but that makes no difference. | |
1242 __ and_(tos, tos, Operand(Smi::FromInt(0x1f))); | |
1243 __ cmp(tos, Operand(Smi::FromInt(max_shift))); | |
1244 deferred->Branch(ge); | |
1245 Register scratch = VirtualFrame::scratch0(); | |
1246 __ mov(scratch, Operand(tos, ASR, kSmiTagSize)); // Untag. | |
1247 __ mov(tos, Operand(Smi::FromInt(int_value))); // Load constant. | |
1248 __ mov(tos, Operand(tos, LSL, scratch)); // Shift constant. | |
1249 deferred->BindExit(); | |
1250 TypeInfo result = TypeInfo::Integer32(); | |
1251 frame_->EmitPush(tos, result); | |
1252 break; | |
1253 } | |
1254 // Fall through! | |
1144 case Token::SHR: | 1255 case Token::SHR: |
1145 case Token::SAR: { | 1256 case Token::SAR: { |
1146 ASSERT(!reversed); | 1257 ASSERT(!reversed); |
1258 TypeInfo result = TypeInfo::Integer32(); | |
1147 Register scratch = VirtualFrame::scratch0(); | 1259 Register scratch = VirtualFrame::scratch0(); |
1148 Register scratch2 = VirtualFrame::scratch1(); | 1260 Register scratch2 = VirtualFrame::scratch1(); |
1149 int shift_value = int_value & 0x1f; // least significant 5 bits | 1261 int shift_value = int_value & 0x1f; // least significant 5 bits |
1150 DeferredCode* deferred = | 1262 DeferredCode* deferred = |
1151 new DeferredInlineSmiOperation(op, shift_value, false, mode, tos); | 1263 new DeferredInlineSmiOperation(op, shift_value, false, mode, tos); |
1152 uint32_t problematic_mask = kSmiTagMask; | 1264 uint32_t problematic_mask = kSmiTagMask; |
1153 // For unsigned shift by zero all negative smis are problematic. | 1265 // For unsigned shift by zero all negative smis are problematic. |
1154 if (shift_value == 0 && op == Token::SHR) problematic_mask |= 0x80000000; | 1266 bool skip_smi_test = both_sides_are_smi; |
1155 __ tst(tos, Operand(problematic_mask)); | 1267 if (shift_value == 0 && op == Token::SHR) { |
1156 deferred->Branch(ne); // Go slow for problematic input. | 1268 problematic_mask |= 0x80000000; |
1269 skip_smi_test = false; | |
1270 } | |
1271 if (!skip_smi_test) { | |
1272 __ tst(tos, Operand(problematic_mask)); | |
1273 deferred->Branch(ne); // Go slow for problematic input. | |
1274 } | |
1157 switch (op) { | 1275 switch (op) { |
1158 case Token::SHL: { | 1276 case Token::SHL: { |
1159 if (shift_value != 0) { | 1277 if (shift_value != 0) { |
1160 int adjusted_shift = shift_value - kSmiTagSize; | 1278 int adjusted_shift = shift_value - kSmiTagSize; |
1161 ASSERT(adjusted_shift >= 0); | 1279 ASSERT(adjusted_shift >= 0); |
1162 if (adjusted_shift != 0) { | 1280 if (adjusted_shift != 0) { |
1163 __ mov(scratch, Operand(tos, LSL, adjusted_shift)); | 1281 __ mov(scratch, Operand(tos, LSL, adjusted_shift)); |
1164 // Check that the *signed* result fits in a smi. | 1282 // Check that the *signed* result fits in a smi. |
1165 __ add(scratch2, scratch, Operand(0x40000000), SetCC); | 1283 __ add(scratch2, scratch, Operand(0x40000000), SetCC); |
1166 deferred->Branch(mi); | 1284 deferred->Branch(mi); |
(...skipping 14 matching lines...) Expand all Loading... | |
1181 __ mov(scratch, Operand(scratch, LSR, shift_value)); | 1299 __ mov(scratch, Operand(scratch, LSR, shift_value)); |
1182 if (shift_value == 1) { | 1300 if (shift_value == 1) { |
1183 // check that the *unsigned* result fits in a smi | 1301 // check that the *unsigned* result fits in a smi |
1184 // neither of the two high-order bits can be set: | 1302 // neither of the two high-order bits can be set: |
1185 // - 0x80000000: high bit would be lost when smi tagging | 1303 // - 0x80000000: high bit would be lost when smi tagging |
1186 // - 0x40000000: this number would convert to negative when | 1304 // - 0x40000000: this number would convert to negative when |
1187 // smi tagging these two cases can only happen with shifts | 1305 // smi tagging these two cases can only happen with shifts |
1188 // by 0 or 1 when handed a valid smi | 1306 // by 0 or 1 when handed a valid smi |
1189 __ tst(scratch, Operand(0xc0000000)); | 1307 __ tst(scratch, Operand(0xc0000000)); |
1190 deferred->Branch(ne); | 1308 deferred->Branch(ne); |
1309 } else { | |
1310 ASSERT(shift_value >= 2); | |
1311 result = TypeInfo::Smi(); // SHR by at least 2 gives a Smi. | |
1191 } | 1312 } |
1192 __ mov(tos, Operand(scratch, LSL, kSmiTagSize)); | 1313 __ mov(tos, Operand(scratch, LSL, kSmiTagSize)); |
1193 } | 1314 } |
1194 break; | 1315 break; |
1195 } | 1316 } |
1196 case Token::SAR: { | 1317 case Token::SAR: { |
1197 // In the ARM instructions set, ASR by immediate 0 means shifting 32 | 1318 // In the ARM instructions set, ASR by immediate 0 means shifting 32 |
1198 // bits. | 1319 // bits. |
1199 if (shift_value != 0) { | 1320 if (shift_value != 0) { |
1200 // Do the shift and the tag removal in one operation. If the shift | 1321 // Do the shift and the tag removal in one operation. If the shift |
1201 // is 31 bits (the highest possible value) then we emit the | 1322 // is 31 bits (the highest possible value) then we emit the |
1202 // instruction as a shift by 0 which means shift arithmetically by | 1323 // instruction as a shift by 0 which means shift arithmetically by |
1203 // 32. | 1324 // 32. |
1204 __ mov(tos, Operand(tos, ASR, (kSmiTagSize + shift_value) & 0x1f)); | 1325 __ mov(tos, Operand(tos, ASR, (kSmiTagSize + shift_value) & 0x1f)); |
1205 // Put tag back. | 1326 // Put tag back. |
1206 __ mov(tos, Operand(tos, LSL, kSmiTagSize)); | 1327 __ mov(tos, Operand(tos, LSL, kSmiTagSize)); |
1328 // SAR by at least 1 gives a Smi. | |
1329 result = TypeInfo::Smi(); | |
1207 } | 1330 } |
1208 break; | 1331 break; |
1209 } | 1332 } |
1210 default: UNREACHABLE(); | 1333 default: UNREACHABLE(); |
1211 } | 1334 } |
1212 deferred->BindExit(); | 1335 deferred->BindExit(); |
1213 frame_->EmitPush(tos); | 1336 frame_->EmitPush(tos, result); |
1214 break; | 1337 break; |
1215 } | 1338 } |
1216 | 1339 |
1217 case Token::MOD: { | 1340 case Token::MOD: { |
1218 ASSERT(!reversed); | 1341 ASSERT(!reversed); |
1219 ASSERT(int_value >= 2); | 1342 ASSERT(int_value >= 2); |
1220 ASSERT(IsPowerOf2(int_value)); | 1343 ASSERT(IsPowerOf2(int_value)); |
1221 DeferredCode* deferred = | 1344 DeferredCode* deferred = |
1222 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 1345 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); |
1223 unsigned mask = (0x80000000u | kSmiTagMask); | 1346 unsigned mask = (0x80000000u | kSmiTagMask); |
1224 __ tst(tos, Operand(mask)); | 1347 __ tst(tos, Operand(mask)); |
1225 deferred->Branch(ne); // Go to deferred code on non-Smis and negative. | 1348 deferred->Branch(ne); // Go to deferred code on non-Smis and negative. |
1226 mask = (int_value << kSmiTagSize) - 1; | 1349 mask = (int_value << kSmiTagSize) - 1; |
1227 __ and_(tos, tos, Operand(mask)); | 1350 __ and_(tos, tos, Operand(mask)); |
1228 deferred->BindExit(); | 1351 deferred->BindExit(); |
1229 frame_->EmitPush(tos); | 1352 // Mod of positive power of 2 Smi gives a Smi if the lhs is an integer. |
1353 frame_->EmitPush( | |
1354 tos, | |
1355 both_sides_are_smi ? TypeInfo::Smi() : TypeInfo::Number()); | |
1230 break; | 1356 break; |
1231 } | 1357 } |
1232 | 1358 |
1233 case Token::MUL: { | 1359 case Token::MUL: { |
1234 ASSERT(IsEasyToMultiplyBy(int_value)); | 1360 ASSERT(IsEasyToMultiplyBy(int_value)); |
1235 DeferredCode* deferred = | 1361 DeferredCode* deferred = |
1236 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | 1362 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); |
1237 unsigned max_smi_that_wont_overflow = Smi::kMaxValue / int_value; | 1363 unsigned max_smi_that_wont_overflow = Smi::kMaxValue / int_value; |
1238 max_smi_that_wont_overflow <<= kSmiTagSize; | 1364 max_smi_that_wont_overflow <<= kSmiTagSize; |
1239 unsigned mask = 0x80000000u; | 1365 unsigned mask = 0x80000000u; |
1240 while ((mask & max_smi_that_wont_overflow) == 0) { | 1366 while ((mask & max_smi_that_wont_overflow) == 0) { |
1241 mask |= mask >> 1; | 1367 mask |= mask >> 1; |
1242 } | 1368 } |
1243 mask |= kSmiTagMask; | 1369 mask |= kSmiTagMask; |
1244 // This does a single mask that checks for a too high value in a | 1370 // This does a single mask that checks for a too high value in a |
1245 // conservative way and for a non-Smi. It also filters out negative | 1371 // conservative way and for a non-Smi. It also filters out negative |
1246 // numbers, unfortunately, but since this code is inline we prefer | 1372 // numbers, unfortunately, but since this code is inline we prefer |
(...skipping 25 matching lines...) Expand all Loading... | |
1272 // sp[0] : y | 1398 // sp[0] : y |
1273 // sp[1] : x | 1399 // sp[1] : x |
1274 // result : cc register | 1400 // result : cc register |
1275 | 1401 |
1276 // Strict only makes sense for equality comparisons. | 1402 // Strict only makes sense for equality comparisons. |
1277 ASSERT(!strict || cc == eq); | 1403 ASSERT(!strict || cc == eq); |
1278 | 1404 |
1279 Register lhs; | 1405 Register lhs; |
1280 Register rhs; | 1406 Register rhs; |
1281 | 1407 |
1408 bool lhs_is_smi; | |
1409 bool rhs_is_smi; | |
1410 | |
1282 // We load the top two stack positions into registers chosen by the virtual | 1411 // We load the top two stack positions into registers chosen by the virtual |
1283 // frame. This should keep the register shuffling to a minimum. | 1412 // frame. This should keep the register shuffling to a minimum. |
1284 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1413 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
1285 if (cc == gt || cc == le) { | 1414 if (cc == gt || cc == le) { |
1286 cc = ReverseCondition(cc); | 1415 cc = ReverseCondition(cc); |
1416 lhs_is_smi = frame_->KnownSmiAt(0); | |
1417 rhs_is_smi = frame_->KnownSmiAt(1); | |
1287 lhs = frame_->PopToRegister(); | 1418 lhs = frame_->PopToRegister(); |
1288 rhs = frame_->PopToRegister(lhs); // Don't pop to the same register again! | 1419 rhs = frame_->PopToRegister(lhs); // Don't pop to the same register again! |
1289 } else { | 1420 } else { |
1421 rhs_is_smi = frame_->KnownSmiAt(0); | |
1422 lhs_is_smi = frame_->KnownSmiAt(1); | |
1290 rhs = frame_->PopToRegister(); | 1423 rhs = frame_->PopToRegister(); |
1291 lhs = frame_->PopToRegister(rhs); // Don't pop to the same register again! | 1424 lhs = frame_->PopToRegister(rhs); // Don't pop to the same register again! |
1292 } | 1425 } |
1293 | 1426 |
1427 bool both_sides_are_smi = (lhs_is_smi && rhs_is_smi); | |
1428 | |
1294 ASSERT(rhs.is(r0) || rhs.is(r1)); | 1429 ASSERT(rhs.is(r0) || rhs.is(r1)); |
1295 ASSERT(lhs.is(r0) || lhs.is(r1)); | 1430 ASSERT(lhs.is(r0) || lhs.is(r1)); |
1296 | 1431 |
1297 // Now we have the two sides in r0 and r1. We flush any other registers | 1432 JumpTarget exit; |
1298 // because the stub doesn't know about register allocation. | |
1299 frame_->SpillAll(); | |
1300 Register scratch = VirtualFrame::scratch0(); | |
1301 __ orr(scratch, lhs, Operand(rhs)); | |
1302 __ tst(scratch, Operand(kSmiTagMask)); | |
1303 JumpTarget smi; | |
1304 smi.Branch(eq); | |
1305 | 1433 |
1306 // Perform non-smi comparison by stub. | 1434 if (!both_sides_are_smi) { |
1307 // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. | 1435 // Now we have the two sides in r0 and r1. We flush any other registers |
1308 // We call with 0 args because there are 0 on the stack. | 1436 // because the stub doesn't know about register allocation. |
1309 if (!rhs.is(r0)) { | 1437 frame_->SpillAll(); |
1310 __ Swap(rhs, lhs, ip); | 1438 Register scratch = VirtualFrame::scratch0(); |
1439 Register smi_test_reg; | |
1440 if (lhs_is_smi) { | |
1441 smi_test_reg = rhs; | |
1442 } else if (rhs_is_smi) { | |
1443 smi_test_reg = lhs; | |
1444 } else { | |
1445 __ orr(scratch, lhs, Operand(rhs)); | |
1446 smi_test_reg = scratch; | |
1447 } | |
1448 __ tst(smi_test_reg, Operand(kSmiTagMask)); | |
1449 JumpTarget smi; | |
1450 smi.Branch(eq); | |
1451 | |
1452 // Perform non-smi comparison by stub. | |
1453 // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. | |
1454 // We call with 0 args because there are 0 on the stack. | |
1455 if (!rhs.is(r0)) { | |
1456 __ Swap(rhs, lhs, ip); | |
1457 } | |
1458 | |
1459 CompareStub stub(cc, strict); | |
1460 frame_->CallStub(&stub, 0); | |
1461 __ cmp(r0, Operand(0)); | |
1462 exit.Jump(); | |
1463 | |
1464 smi.Bind(); | |
1311 } | 1465 } |
1312 | 1466 |
1313 CompareStub stub(cc, strict); | |
1314 frame_->CallStub(&stub, 0); | |
1315 __ cmp(r0, Operand(0)); | |
1316 JumpTarget exit; | |
1317 exit.Jump(); | |
1318 | |
1319 // Do smi comparisons by pointer comparison. | 1467 // Do smi comparisons by pointer comparison. |
1320 smi.Bind(); | |
1321 __ cmp(lhs, Operand(rhs)); | 1468 __ cmp(lhs, Operand(rhs)); |
1322 | 1469 |
1323 exit.Bind(); | 1470 exit.Bind(); |
1324 cc_reg_ = cc; | 1471 cc_reg_ = cc; |
1325 } | 1472 } |
1326 | 1473 |
1327 | 1474 |
1328 // Call the function on the stack with the given arguments. | 1475 // Call the function on the stack with the given arguments. |
1329 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1476 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
1330 CallFunctionFlags flags, | 1477 CallFunctionFlags flags, |
(...skipping 752 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2083 } | 2230 } |
2084 | 2231 |
2085 // If the test is never true there is no need to compile the test or | 2232 // If the test is never true there is no need to compile the test or |
2086 // body. | 2233 // body. |
2087 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 2234 ConditionAnalysis info = AnalyzeCondition(node->cond()); |
2088 if (info == ALWAYS_FALSE) return; | 2235 if (info == ALWAYS_FALSE) return; |
2089 | 2236 |
2090 node->break_target()->SetExpectedHeight(); | 2237 node->break_target()->SetExpectedHeight(); |
2091 IncrementLoopNesting(); | 2238 IncrementLoopNesting(); |
2092 | 2239 |
2240 // We know that the loop index is a smi if it is not modified in the | |
2241 // loop body and it is checked against a constant limit in the loop | |
2242 // condition. In this case, we reset the static type information of the | |
2243 // loop index to smi before compiling the body, the update expression, and | |
2244 // the bottom check of the loop condition. | |
2245 TypeInfoCodeGenState type_info_scope(this, | |
2246 node->is_fast_smi_loop() ? | |
2247 node->loop_variable()->slot() : | |
2248 NULL, | |
2249 TypeInfo::Smi()); | |
2250 | |
2093 // If there is no update statement, label the top of the loop with the | 2251 // If there is no update statement, label the top of the loop with the |
2094 // continue target, otherwise with the loop target. | 2252 // continue target, otherwise with the loop target. |
2095 JumpTarget loop(JumpTarget::BIDIRECTIONAL); | 2253 JumpTarget loop(JumpTarget::BIDIRECTIONAL); |
2096 if (node->next() == NULL) { | 2254 if (node->next() == NULL) { |
2097 node->continue_target()->SetExpectedHeight(); | 2255 node->continue_target()->SetExpectedHeight(); |
2098 node->continue_target()->Bind(); | 2256 node->continue_target()->Bind(); |
2099 } else { | 2257 } else { |
2100 node->continue_target()->SetExpectedHeight(); | 2258 node->continue_target()->SetExpectedHeight(); |
2101 loop.Bind(); | 2259 loop.Bind(); |
2102 } | 2260 } |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2803 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2961 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
2804 } else { | 2962 } else { |
2805 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2963 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
2806 } | 2964 } |
2807 | 2965 |
2808 done.Bind(); | 2966 done.Bind(); |
2809 frame_->EmitPush(r0); | 2967 frame_->EmitPush(r0); |
2810 | 2968 |
2811 } else { | 2969 } else { |
2812 Register scratch = VirtualFrame::scratch0(); | 2970 Register scratch = VirtualFrame::scratch0(); |
2813 frame_->EmitPush(SlotOperand(slot, scratch)); | 2971 TypeInfo info = type_info(slot); |
2972 frame_->EmitPush(SlotOperand(slot, scratch), info); | |
2814 if (slot->var()->mode() == Variable::CONST) { | 2973 if (slot->var()->mode() == Variable::CONST) { |
2815 // Const slots may contain 'the hole' value (the constant hasn't been | 2974 // Const slots may contain 'the hole' value (the constant hasn't been |
2816 // initialized yet) which needs to be converted into the 'undefined' | 2975 // initialized yet) which needs to be converted into the 'undefined' |
2817 // value. | 2976 // value. |
2818 Comment cmnt(masm_, "[ Unhole const"); | 2977 Comment cmnt(masm_, "[ Unhole const"); |
2819 frame_->EmitPop(scratch); | 2978 frame_->EmitPop(scratch); |
2820 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2979 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
2821 __ cmp(scratch, ip); | 2980 __ cmp(scratch, ip); |
2822 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex, eq); | 2981 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex, eq); |
2823 frame_->EmitPush(scratch); | 2982 frame_->EmitPush(scratch); |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3093 ASSERT_EQ(original_height + 1, frame_->height()); | 3252 ASSERT_EQ(original_height + 1, frame_->height()); |
3094 } | 3253 } |
3095 | 3254 |
3096 | 3255 |
3097 void CodeGenerator::VisitLiteral(Literal* node) { | 3256 void CodeGenerator::VisitLiteral(Literal* node) { |
3098 #ifdef DEBUG | 3257 #ifdef DEBUG |
3099 int original_height = frame_->height(); | 3258 int original_height = frame_->height(); |
3100 #endif | 3259 #endif |
3101 Comment cmnt(masm_, "[ Literal"); | 3260 Comment cmnt(masm_, "[ Literal"); |
3102 Register reg = frame_->GetTOSRegister(); | 3261 Register reg = frame_->GetTOSRegister(); |
3262 bool is_smi = node->handle()->IsSmi(); | |
3103 __ mov(reg, Operand(node->handle())); | 3263 __ mov(reg, Operand(node->handle())); |
3104 frame_->EmitPush(reg); | 3264 frame_->EmitPush(reg, is_smi ? TypeInfo::Smi() : TypeInfo::Unknown()); |
3105 ASSERT_EQ(original_height + 1, frame_->height()); | 3265 ASSERT_EQ(original_height + 1, frame_->height()); |
3106 } | 3266 } |
3107 | 3267 |
3108 | 3268 |
3109 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 3269 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
3110 #ifdef DEBUG | 3270 #ifdef DEBUG |
3111 int original_height = frame_->height(); | 3271 int original_height = frame_->height(); |
3112 #endif | 3272 #endif |
3113 VirtualFrame::SpilledScope spilled_scope(frame_); | 3273 VirtualFrame::SpilledScope spilled_scope(frame_); |
3114 Comment cmnt(masm_, "[ RexExp Literal"); | 3274 Comment cmnt(masm_, "[ RexExp Literal"); |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3325 Literal* literal = node->value()->AsLiteral(); | 3485 Literal* literal = node->value()->AsLiteral(); |
3326 bool overwrite_value = | 3486 bool overwrite_value = |
3327 (node->value()->AsBinaryOperation() != NULL && | 3487 (node->value()->AsBinaryOperation() != NULL && |
3328 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3488 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
3329 if (literal != NULL && literal->handle()->IsSmi()) { | 3489 if (literal != NULL && literal->handle()->IsSmi()) { |
3330 SmiOperation(node->binary_op(), | 3490 SmiOperation(node->binary_op(), |
3331 literal->handle(), | 3491 literal->handle(), |
3332 false, | 3492 false, |
3333 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3493 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
3334 } else { | 3494 } else { |
3495 GenerateInlineSmi inline_smi = | |
3496 loop_nesting() > 0 ? GENERATE_INLINE_SMI : DONT_GENERATE_INLINE_SMI; | |
3497 if (literal != NULL) inline_smi = DONT_GENERATE_INLINE_SMI; | |
Søren Thygesen Gjesse
2010/06/02 09:24:01
Maybe assert !literal.IsSmi() when it is != NULL (
| |
3335 Load(node->value()); | 3498 Load(node->value()); |
3336 VirtualFrameBinaryOperation( | 3499 VirtualFrameBinaryOperation( |
3337 node->binary_op(), overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3500 node->binary_op(), |
3501 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, | |
3502 inline_smi); | |
3338 } | 3503 } |
3339 } else { | 3504 } else { |
3340 Load(node->value()); | 3505 Load(node->value()); |
3341 } | 3506 } |
3342 | 3507 |
3343 // Perform the assignment. | 3508 // Perform the assignment. |
3344 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { | 3509 if (var->mode() != Variable::CONST || node->op() == Token::INIT_CONST) { |
3345 CodeForSourcePosition(node->position()); | 3510 CodeForSourcePosition(node->position()); |
3346 StoreToSlot(slot, | 3511 StoreToSlot(slot, |
3347 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); | 3512 node->op() == Token::INIT_CONST ? CONST_INIT : NOT_CONST_INIT); |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3418 Literal* literal = node->value()->AsLiteral(); | 3583 Literal* literal = node->value()->AsLiteral(); |
3419 bool overwrite_value = | 3584 bool overwrite_value = |
3420 (node->value()->AsBinaryOperation() != NULL && | 3585 (node->value()->AsBinaryOperation() != NULL && |
3421 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3586 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
3422 if (literal != NULL && literal->handle()->IsSmi()) { | 3587 if (literal != NULL && literal->handle()->IsSmi()) { |
3423 SmiOperation(node->binary_op(), | 3588 SmiOperation(node->binary_op(), |
3424 literal->handle(), | 3589 literal->handle(), |
3425 false, | 3590 false, |
3426 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3591 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
3427 } else { | 3592 } else { |
3593 GenerateInlineSmi inline_smi = | |
3594 loop_nesting() > 0 ? GENERATE_INLINE_SMI : DONT_GENERATE_INLINE_SMI; | |
3595 if (literal != NULL) inline_smi = DONT_GENERATE_INLINE_SMI; | |
3428 Load(node->value()); | 3596 Load(node->value()); |
3429 VirtualFrameBinaryOperation( | 3597 VirtualFrameBinaryOperation( |
3430 node->binary_op(), overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3598 node->binary_op(), |
3599 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, | |
3600 inline_smi); | |
3431 } | 3601 } |
3432 } else { | 3602 } else { |
3433 // For non-compound assignment just load the right-hand side. | 3603 // For non-compound assignment just load the right-hand side. |
3434 Load(node->value()); | 3604 Load(node->value()); |
3435 } | 3605 } |
3436 | 3606 |
3437 // Stack layout: | 3607 // Stack layout: |
3438 // [tos] : value | 3608 // [tos] : value |
3439 // [tos+1] : receiver (only materialized if non-trivial) | 3609 // [tos+1] : receiver (only materialized if non-trivial) |
3440 // [tos+2] : receiver if at the end of an initialization block | 3610 // [tos+2] : receiver if at the end of an initialization block |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3525 Literal* literal = node->value()->AsLiteral(); | 3695 Literal* literal = node->value()->AsLiteral(); |
3526 bool overwrite_value = | 3696 bool overwrite_value = |
3527 (node->value()->AsBinaryOperation() != NULL && | 3697 (node->value()->AsBinaryOperation() != NULL && |
3528 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3698 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
3529 if (literal != NULL && literal->handle()->IsSmi()) { | 3699 if (literal != NULL && literal->handle()->IsSmi()) { |
3530 SmiOperation(node->binary_op(), | 3700 SmiOperation(node->binary_op(), |
3531 literal->handle(), | 3701 literal->handle(), |
3532 false, | 3702 false, |
3533 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3703 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); |
3534 } else { | 3704 } else { |
3705 GenerateInlineSmi inline_smi = | |
3706 loop_nesting() > 0 ? GENERATE_INLINE_SMI : DONT_GENERATE_INLINE_SMI; | |
3707 if (literal != NULL) inline_smi = DONT_GENERATE_INLINE_SMI; | |
3535 Load(node->value()); | 3708 Load(node->value()); |
3536 VirtualFrameBinaryOperation( | 3709 VirtualFrameBinaryOperation( |
3537 node->binary_op(), overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3710 node->binary_op(), |
3711 overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE, | |
3712 inline_smi); | |
3538 } | 3713 } |
3539 } else { | 3714 } else { |
3540 // For non-compound assignment just load the right-hand side. | 3715 // For non-compound assignment just load the right-hand side. |
3541 Load(node->value()); | 3716 Load(node->value()); |
3542 } | 3717 } |
3543 | 3718 |
3544 // Stack layout: | 3719 // Stack layout: |
3545 // [tos] : value | 3720 // [tos] : value |
3546 // [tos+1] : key | 3721 // [tos+1] : key |
3547 // [tos+2] : receiver | 3722 // [tos+2] : receiver |
(...skipping 1531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5079 #ifdef DEBUG | 5254 #ifdef DEBUG |
5080 int original_height = frame_->height(); | 5255 int original_height = frame_->height(); |
5081 #endif | 5256 #endif |
5082 Comment cmnt(masm_, "[ CountOperation"); | 5257 Comment cmnt(masm_, "[ CountOperation"); |
5083 | 5258 |
5084 bool is_postfix = node->is_postfix(); | 5259 bool is_postfix = node->is_postfix(); |
5085 bool is_increment = node->op() == Token::INC; | 5260 bool is_increment = node->op() == Token::INC; |
5086 | 5261 |
5087 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 5262 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
5088 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 5263 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
5264 bool is_slot = (var != NULL && var->mode() == Variable::VAR); | |
5089 | 5265 |
5090 if (is_postfix) { | 5266 if (!is_const && is_slot && type_info(var->slot()).IsSmi()) { |
5267 // The type info declares that this variable is always a Smi. That | |
5268 // means it is a Smi both before and after the increment/decrement. | |
5269 // Lets make use of that to make a very minimal count. | |
5270 Reference target(this, node->expression(), !is_const); | |
5271 ASSERT(!target.is_illegal()); | |
5272 target.GetValue(); // Pushes the value. | |
5273 Register value = frame_->PopToRegister(); | |
5274 if (is_postfix) frame_->EmitPush(value); | |
5275 if (is_increment) { | |
5276 __ add(value, value, Operand(Smi::FromInt(1))); | |
5277 } else { | |
5278 __ sub(value, value, Operand(Smi::FromInt(1))); | |
5279 } | |
5280 frame_->EmitPush(value); | |
5281 target.SetValue(NOT_CONST_INIT); | |
5282 if (is_postfix) frame_->Pop(); | |
5283 ASSERT_EQ(original_height + 1, frame_->height()); | |
5284 return; | |
5285 } | |
5286 | |
5287 // If it's a postfix expression and its result is not ignored and the | |
5288 // reference is non-trivial, then push a placeholder on the stack now | |
5289 // to hold the result of the expression. | |
5290 bool placeholder_pushed = false; | |
5291 if (!is_slot && is_postfix) { | |
5091 frame_->EmitPush(Operand(Smi::FromInt(0))); | 5292 frame_->EmitPush(Operand(Smi::FromInt(0))); |
5293 placeholder_pushed = true; | |
5092 } | 5294 } |
5093 | 5295 |
5094 // A constant reference is not saved to, so a constant reference is not a | 5296 // A constant reference is not saved to, so a constant reference is not a |
5095 // compound assignment reference. | 5297 // compound assignment reference. |
5096 { Reference target(this, node->expression(), !is_const); | 5298 { Reference target(this, node->expression(), !is_const); |
5097 if (target.is_illegal()) { | 5299 if (target.is_illegal()) { |
5098 // Spoof the virtual frame to have the expected height (one higher | 5300 // Spoof the virtual frame to have the expected height (one higher |
5099 // than on entry). | 5301 // than on entry). |
5100 if (!is_postfix) { | 5302 if (!placeholder_pushed) frame_->EmitPush(Operand(Smi::FromInt(0))); |
5101 frame_->EmitPush(Operand(Smi::FromInt(0))); | |
5102 } | |
5103 ASSERT_EQ(original_height + 1, frame_->height()); | 5303 ASSERT_EQ(original_height + 1, frame_->height()); |
5104 return; | 5304 return; |
5105 } | 5305 } |
5306 | |
5106 // This pushes 0, 1 or 2 words on the object to be used later when updating | 5307 // This pushes 0, 1 or 2 words on the object to be used later when updating |
5107 // the target. It also pushes the current value of the target. | 5308 // the target. It also pushes the current value of the target. |
5108 target.GetValue(); | 5309 target.GetValue(); |
5109 | 5310 |
5110 JumpTarget slow; | 5311 JumpTarget slow; |
5111 JumpTarget exit; | 5312 JumpTarget exit; |
5112 | 5313 |
5314 Register value = frame_->PopToRegister(); | |
5315 | |
5316 // Postfix: Store the old value as the result. | |
5317 if (placeholder_pushed) { | |
5318 frame_->SetElementAt(value, target.size()); | |
5319 } else if (is_postfix) { | |
5320 frame_->EmitPush(value); | |
5321 __ mov(VirtualFrame::scratch0(), value); | |
5322 value = VirtualFrame::scratch0(); | |
5323 } | |
5324 | |
5113 // Check for smi operand. | 5325 // Check for smi operand. |
5114 Register value = frame_->PopToRegister(); | |
5115 __ tst(value, Operand(kSmiTagMask)); | 5326 __ tst(value, Operand(kSmiTagMask)); |
5116 slow.Branch(ne); | 5327 slow.Branch(ne); |
5117 | 5328 |
5118 // Postfix: Store the old value as the result. | |
5119 if (is_postfix) { | |
5120 frame_->SetElementAt(value, target.size()); | |
5121 } | |
5122 | |
5123 // Perform optimistic increment/decrement. | 5329 // Perform optimistic increment/decrement. |
5124 if (is_increment) { | 5330 if (is_increment) { |
5125 __ add(value, value, Operand(Smi::FromInt(1)), SetCC); | 5331 __ add(value, value, Operand(Smi::FromInt(1)), SetCC); |
5126 } else { | 5332 } else { |
5127 __ sub(value, value, Operand(Smi::FromInt(1)), SetCC); | 5333 __ sub(value, value, Operand(Smi::FromInt(1)), SetCC); |
5128 } | 5334 } |
5129 | 5335 |
5130 // If the increment/decrement didn't overflow, we're done. | 5336 // If the increment/decrement didn't overflow, we're done. |
5131 exit.Branch(vc); | 5337 exit.Branch(vc); |
5132 | 5338 |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5293 bool overwrite_left = | 5499 bool overwrite_left = |
5294 (node->left()->AsBinaryOperation() != NULL && | 5500 (node->left()->AsBinaryOperation() != NULL && |
5295 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5501 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); |
5296 bool overwrite_right = | 5502 bool overwrite_right = |
5297 (node->right()->AsBinaryOperation() != NULL && | 5503 (node->right()->AsBinaryOperation() != NULL && |
5298 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); | 5504 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); |
5299 | 5505 |
5300 if (rliteral != NULL && rliteral->handle()->IsSmi()) { | 5506 if (rliteral != NULL && rliteral->handle()->IsSmi()) { |
5301 VirtualFrame::RegisterAllocationScope scope(this); | 5507 VirtualFrame::RegisterAllocationScope scope(this); |
5302 Load(node->left()); | 5508 Load(node->left()); |
5509 if (frame_->KnownSmiAt(0)) overwrite_left = false; | |
5303 SmiOperation(node->op(), | 5510 SmiOperation(node->op(), |
5304 rliteral->handle(), | 5511 rliteral->handle(), |
5305 false, | 5512 false, |
5306 overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); | 5513 overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); |
5307 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { | 5514 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { |
5308 VirtualFrame::RegisterAllocationScope scope(this); | 5515 VirtualFrame::RegisterAllocationScope scope(this); |
5309 Load(node->right()); | 5516 Load(node->right()); |
5517 if (frame_->KnownSmiAt(0)) overwrite_right = false; | |
5310 SmiOperation(node->op(), | 5518 SmiOperation(node->op(), |
5311 lliteral->handle(), | 5519 lliteral->handle(), |
5312 true, | 5520 true, |
5313 overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); | 5521 overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); |
5314 } else { | 5522 } else { |
5523 GenerateInlineSmi inline_smi = | |
5524 loop_nesting() > 0 ? GENERATE_INLINE_SMI : DONT_GENERATE_INLINE_SMI; | |
5525 if (lliteral != NULL) inline_smi = DONT_GENERATE_INLINE_SMI; | |
5526 if (rliteral != NULL) inline_smi = DONT_GENERATE_INLINE_SMI; | |
5315 VirtualFrame::RegisterAllocationScope scope(this); | 5527 VirtualFrame::RegisterAllocationScope scope(this); |
5316 OverwriteMode overwrite_mode = NO_OVERWRITE; | 5528 OverwriteMode overwrite_mode = NO_OVERWRITE; |
5317 if (overwrite_left) { | 5529 if (overwrite_left) { |
5318 overwrite_mode = OVERWRITE_LEFT; | 5530 overwrite_mode = OVERWRITE_LEFT; |
5319 } else if (overwrite_right) { | 5531 } else if (overwrite_right) { |
5320 overwrite_mode = OVERWRITE_RIGHT; | 5532 overwrite_mode = OVERWRITE_RIGHT; |
5321 } | 5533 } |
5322 Load(node->left()); | 5534 Load(node->left()); |
5323 Load(node->right()); | 5535 Load(node->right()); |
5324 VirtualFrameBinaryOperation(node->op(), overwrite_mode); | 5536 VirtualFrameBinaryOperation(node->op(), overwrite_mode, inline_smi); |
5325 } | 5537 } |
5326 } | 5538 } |
5327 ASSERT(!has_valid_frame() || | 5539 ASSERT(!has_valid_frame() || |
5328 (has_cc() && frame_->height() == original_height) || | 5540 (has_cc() && frame_->height() == original_height) || |
5329 (!has_cc() && frame_->height() == original_height + 1)); | 5541 (!has_cc() && frame_->height() == original_height + 1)); |
5330 } | 5542 } |
5331 | 5543 |
5332 | 5544 |
5333 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 5545 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
5334 #ifdef DEBUG | 5546 #ifdef DEBUG |
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5806 } else { | 6018 } else { |
5807 // Inline the keyed load. | 6019 // Inline the keyed load. |
5808 Comment cmnt(masm_, "[ Inlined load from keyed property"); | 6020 Comment cmnt(masm_, "[ Inlined load from keyed property"); |
5809 | 6021 |
5810 // Counter will be decremented in the deferred code. Placed here to avoid | 6022 // Counter will be decremented in the deferred code. Placed here to avoid |
5811 // having it in the instruction stream below where patching will occur. | 6023 // having it in the instruction stream below where patching will occur. |
5812 __ IncrementCounter(&Counters::keyed_load_inline, 1, | 6024 __ IncrementCounter(&Counters::keyed_load_inline, 1, |
5813 frame_->scratch0(), frame_->scratch1()); | 6025 frame_->scratch0(), frame_->scratch1()); |
5814 | 6026 |
5815 // Load the key and receiver from the stack. | 6027 // Load the key and receiver from the stack. |
6028 bool key_is_known_smi = frame_->KnownSmiAt(0); | |
5816 Register key = frame_->PopToRegister(); | 6029 Register key = frame_->PopToRegister(); |
5817 Register receiver = frame_->PopToRegister(key); | 6030 Register receiver = frame_->PopToRegister(key); |
5818 VirtualFrame::SpilledScope spilled(frame_); | 6031 VirtualFrame::SpilledScope spilled(frame_); |
5819 | 6032 |
5820 // The deferred code expects key and receiver in registers. | 6033 // The deferred code expects key and receiver in registers. |
5821 DeferredReferenceGetKeyedValue* deferred = | 6034 DeferredReferenceGetKeyedValue* deferred = |
5822 new DeferredReferenceGetKeyedValue(key, receiver); | 6035 new DeferredReferenceGetKeyedValue(key, receiver); |
5823 | 6036 |
5824 // Check that the receiver is a heap object. | 6037 // Check that the receiver is a heap object. |
5825 __ tst(receiver, Operand(kSmiTagMask)); | 6038 __ tst(receiver, Operand(kSmiTagMask)); |
5826 deferred->Branch(eq); | 6039 deferred->Branch(eq); |
5827 | 6040 |
5828 // The following instructions are the part of the inlined load keyed | 6041 // The following instructions are the part of the inlined load keyed |
5829 // property code which can be patched. Therefore the exact number of | 6042 // property code which can be patched. Therefore the exact number of |
5830 // instructions generated need to be fixed, so the constant pool is blocked | 6043 // instructions generated need to be fixed, so the constant pool is blocked |
5831 // while generating this code. | 6044 // while generating this code. |
5832 { Assembler::BlockConstPoolScope block_const_pool(masm_); | 6045 { Assembler::BlockConstPoolScope block_const_pool(masm_); |
5833 Register scratch1 = VirtualFrame::scratch0(); | 6046 Register scratch1 = VirtualFrame::scratch0(); |
5834 Register scratch2 = VirtualFrame::scratch1(); | 6047 Register scratch2 = VirtualFrame::scratch1(); |
5835 // Check the map. The null map used below is patched by the inline cache | 6048 // Check the map. The null map used below is patched by the inline cache |
5836 // code. | 6049 // code. |
5837 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 6050 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
6051 | |
6052 // Check that the key is a smi. | |
6053 if (!key_is_known_smi) { | |
6054 __ tst(key, Operand(kSmiTagMask)); | |
6055 deferred->Branch(ne); | |
6056 } | |
6057 | |
5838 #ifdef DEBUG | 6058 #ifdef DEBUG |
5839 Label check_inlined_codesize; | 6059 Label check_inlined_codesize; |
5840 masm_->bind(&check_inlined_codesize); | 6060 masm_->bind(&check_inlined_codesize); |
5841 #endif | 6061 #endif |
5842 __ mov(scratch2, Operand(Factory::null_value())); | 6062 __ mov(scratch2, Operand(Factory::null_value())); |
5843 __ cmp(scratch1, scratch2); | 6063 __ cmp(scratch1, scratch2); |
5844 deferred->Branch(ne); | 6064 deferred->Branch(ne); |
5845 | 6065 |
5846 // Check that the key is a smi. | |
5847 __ tst(key, Operand(kSmiTagMask)); | |
5848 deferred->Branch(ne); | |
5849 | |
5850 // Get the elements array from the receiver and check that it | 6066 // Get the elements array from the receiver and check that it |
5851 // is not a dictionary. | 6067 // is not a dictionary. |
5852 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 6068 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
5853 __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); | 6069 __ ldr(scratch2, FieldMemOperand(scratch1, JSObject::kMapOffset)); |
5854 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 6070 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
5855 __ cmp(scratch2, ip); | 6071 __ cmp(scratch2, ip); |
5856 deferred->Branch(ne); | 6072 deferred->Branch(ne); |
5857 | 6073 |
5858 // Check that key is within bounds. Use unsigned comparison to handle | 6074 // Check that key is within bounds. Use unsigned comparison to handle |
5859 // negative keys. | 6075 // negative keys. |
(...skipping 4408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
10268 __ bind(&string_add_runtime); | 10484 __ bind(&string_add_runtime); |
10269 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 10485 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
10270 } | 10486 } |
10271 | 10487 |
10272 | 10488 |
10273 #undef __ | 10489 #undef __ |
10274 | 10490 |
10275 } } // namespace v8::internal | 10491 } } // namespace v8::internal |
10276 | 10492 |
10277 #endif // V8_TARGET_ARCH_ARM | 10493 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |