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 25 matching lines...) Expand all Loading... |
36 #include "ic-inl.h" | 36 #include "ic-inl.h" |
37 #include "parser.h" | 37 #include "parser.h" |
38 #include "regexp-macro-assembler.h" | 38 #include "regexp-macro-assembler.h" |
39 #include "register-allocator-inl.h" | 39 #include "register-allocator-inl.h" |
40 #include "scopes.h" | 40 #include "scopes.h" |
41 #include "virtual-frame-inl.h" | 41 #include "virtual-frame-inl.h" |
42 | 42 |
43 namespace v8 { | 43 namespace v8 { |
44 namespace internal { | 44 namespace internal { |
45 | 45 |
46 #define __ ACCESS_MASM(masm_) | 46 #define __ ACCESS_MASM(masm) |
47 | 47 |
48 // ------------------------------------------------------------------------- | 48 // ------------------------------------------------------------------------- |
49 // Platform-specific DeferredCode functions. | 49 // Platform-specific FrameRegisterState functions. |
50 | 50 |
51 void DeferredCode::SaveRegisters() { | 51 void FrameRegisterState::Save(MacroAssembler* masm) const { |
52 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { | 52 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
53 int action = registers_[i]; | 53 int action = registers_[i]; |
54 if (action == kPush) { | 54 if (action == kPush) { |
55 __ push(RegisterAllocator::ToRegister(i)); | 55 __ push(RegisterAllocator::ToRegister(i)); |
56 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { | 56 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { |
57 __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); | 57 __ movq(Operand(rbp, action), RegisterAllocator::ToRegister(i)); |
58 } | 58 } |
59 } | 59 } |
60 } | 60 } |
61 | 61 |
62 | 62 |
63 void DeferredCode::RestoreRegisters() { | 63 void FrameRegisterState::Restore(MacroAssembler* masm) const { |
64 // Restore registers in reverse order due to the stack. | 64 // Restore registers in reverse order due to the stack. |
65 for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) { | 65 for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) { |
66 int action = registers_[i]; | 66 int action = registers_[i]; |
67 if (action == kPush) { | 67 if (action == kPush) { |
68 __ pop(RegisterAllocator::ToRegister(i)); | 68 __ pop(RegisterAllocator::ToRegister(i)); |
69 } else if (action != kIgnore) { | 69 } else if (action != kIgnore) { |
70 action &= ~kSyncedFlag; | 70 action &= ~kSyncedFlag; |
71 __ movq(RegisterAllocator::ToRegister(i), Operand(rbp, action)); | 71 __ movq(RegisterAllocator::ToRegister(i), Operand(rbp, action)); |
72 } | 72 } |
73 } | 73 } |
74 } | 74 } |
75 | 75 |
76 | 76 |
| 77 #undef __ |
| 78 #define __ ACCESS_MASM(masm_) |
| 79 |
| 80 // ------------------------------------------------------------------------- |
| 81 // Platform-specific DeferredCode functions. |
| 82 |
| 83 void DeferredCode::SaveRegisters() { |
| 84 frame_state_.Save(masm_); |
| 85 } |
| 86 |
| 87 |
| 88 void DeferredCode::RestoreRegisters() { |
| 89 frame_state_.Restore(masm_); |
| 90 } |
| 91 |
| 92 |
| 93 // ------------------------------------------------------------------------- |
| 94 // Platform-specific RuntimeCallHelper functions. |
| 95 |
| 96 void VirtualFrameRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
| 97 frame_state_->Save(masm); |
| 98 } |
| 99 |
| 100 |
| 101 void VirtualFrameRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
| 102 frame_state_->Restore(masm); |
| 103 } |
| 104 |
| 105 |
| 106 void ICRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
| 107 masm->EnterInternalFrame(); |
| 108 } |
| 109 |
| 110 |
| 111 void ICRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
| 112 masm->LeaveInternalFrame(); |
| 113 } |
| 114 |
| 115 |
77 // ------------------------------------------------------------------------- | 116 // ------------------------------------------------------------------------- |
78 // CodeGenState implementation. | 117 // CodeGenState implementation. |
79 | 118 |
80 CodeGenState::CodeGenState(CodeGenerator* owner) | 119 CodeGenState::CodeGenState(CodeGenerator* owner) |
81 : owner_(owner), | 120 : owner_(owner), |
82 destination_(NULL), | 121 destination_(NULL), |
83 previous_(NULL) { | 122 previous_(NULL) { |
84 owner_->set_state(this); | 123 owner_->set_state(this); |
85 } | 124 } |
86 | 125 |
(...skipping 3879 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3966 | 4005 |
3967 __ bind(&exit); | 4006 __ bind(&exit); |
3968 result.set_type_info(TypeInfo::Smi()); | 4007 result.set_type_info(TypeInfo::Smi()); |
3969 if (FLAG_debug_code) { | 4008 if (FLAG_debug_code) { |
3970 __ AbortIfNotSmi(result.reg()); | 4009 __ AbortIfNotSmi(result.reg()); |
3971 } | 4010 } |
3972 frame_->Push(&result); | 4011 frame_->Push(&result); |
3973 } | 4012 } |
3974 | 4013 |
3975 | 4014 |
3976 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 4015 class DeferredStringCharCodeAt : public DeferredCode { |
3977 Comment(masm_, "[ GenerateFastCharCodeAt"); | 4016 public: |
| 4017 DeferredStringCharCodeAt(Register object, |
| 4018 Register index, |
| 4019 Register scratch, |
| 4020 Register result) |
| 4021 : result_(result), |
| 4022 char_code_at_generator_(object, |
| 4023 index, |
| 4024 scratch, |
| 4025 result, |
| 4026 &need_conversion_, |
| 4027 &need_conversion_, |
| 4028 &index_out_of_range_, |
| 4029 STRING_ANY_NUMBER_INDEX) {} |
| 4030 |
| 4031 StringCharCodeAtGenerator* fast_case_generator() { |
| 4032 return &char_code_at_generator_; |
| 4033 } |
| 4034 |
| 4035 virtual void Generate() { |
| 4036 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 4037 char_code_at_generator_.GenerateSlow(masm(), call_helper); |
| 4038 |
| 4039 __ bind(&need_conversion_); |
| 4040 // Move the undefined value into the result register, which will |
| 4041 // trigger conversion. |
| 4042 __ LoadRoot(result_, Heap::kUndefinedValueRootIndex); |
| 4043 __ jmp(exit_label()); |
| 4044 |
| 4045 __ bind(&index_out_of_range_); |
| 4046 // When the index is out of range, the spec requires us to return |
| 4047 // NaN. |
| 4048 __ LoadRoot(result_, Heap::kNanValueRootIndex); |
| 4049 __ jmp(exit_label()); |
| 4050 } |
| 4051 |
| 4052 private: |
| 4053 Register result_; |
| 4054 |
| 4055 Label need_conversion_; |
| 4056 Label index_out_of_range_; |
| 4057 |
| 4058 StringCharCodeAtGenerator char_code_at_generator_; |
| 4059 }; |
| 4060 |
| 4061 |
| 4062 // This generates code that performs a String.prototype.charCodeAt() call |
| 4063 // or returns a smi in order to trigger conversion. |
| 4064 void CodeGenerator::GenerateStringCharCodeAt(ZoneList<Expression*>* args) { |
| 4065 Comment(masm_, "[ GenerateStringCharCodeAt"); |
3978 ASSERT(args->length() == 2); | 4066 ASSERT(args->length() == 2); |
3979 | 4067 |
3980 Load(args->at(0)); | 4068 Load(args->at(0)); |
3981 Load(args->at(1)); | 4069 Load(args->at(1)); |
3982 Result index = frame_->Pop(); | 4070 Result index = frame_->Pop(); |
3983 Result object = frame_->Pop(); | 4071 Result object = frame_->Pop(); |
3984 | |
3985 // We will mutate the index register and possibly the object register. | |
3986 // The case where they are somehow the same register is handled | |
3987 // because we only mutate them in the case where the receiver is a | |
3988 // heap object and the index is not. | |
3989 object.ToRegister(); | 4072 object.ToRegister(); |
3990 index.ToRegister(); | 4073 index.ToRegister(); |
| 4074 // We might mutate the object register. |
3991 frame_->Spill(object.reg()); | 4075 frame_->Spill(object.reg()); |
3992 frame_->Spill(index.reg()); | |
3993 | 4076 |
3994 // We need two extra registers. | 4077 // We need two extra registers. |
3995 Result result = allocator()->Allocate(); | 4078 Result result = allocator()->Allocate(); |
3996 ASSERT(result.is_valid()); | 4079 ASSERT(result.is_valid()); |
3997 Result scratch = allocator()->Allocate(); | 4080 Result scratch = allocator()->Allocate(); |
3998 ASSERT(scratch.is_valid()); | 4081 ASSERT(scratch.is_valid()); |
3999 | 4082 |
4000 // There is no virtual frame effect from here up to the final result | 4083 DeferredStringCharCodeAt* deferred = |
4001 // push. | 4084 new DeferredStringCharCodeAt(object.reg(), |
4002 Label slow_case; | 4085 index.reg(), |
4003 Label exit; | 4086 scratch.reg(), |
4004 StringHelper::GenerateFastCharCodeAt(masm_, | 4087 result.reg()); |
4005 object.reg(), | 4088 deferred->fast_case_generator()->GenerateFast(masm_); |
4006 index.reg(), | 4089 deferred->BindExit(); |
4007 scratch.reg(), | |
4008 result.reg(), | |
4009 &slow_case, | |
4010 &slow_case, | |
4011 &slow_case, | |
4012 &slow_case); | |
4013 __ jmp(&exit); | |
4014 | |
4015 __ bind(&slow_case); | |
4016 // Move the undefined value into the result register, which will | |
4017 // trigger the slow case. | |
4018 __ LoadRoot(result.reg(), Heap::kUndefinedValueRootIndex); | |
4019 | |
4020 __ bind(&exit); | |
4021 frame_->Push(&result); | 4090 frame_->Push(&result); |
4022 } | 4091 } |
4023 | 4092 |
4024 | 4093 |
4025 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { | 4094 class DeferredStringCharFromCode : public DeferredCode { |
4026 Comment(masm_, "[ GenerateCharFromCode"); | 4095 public: |
| 4096 DeferredStringCharFromCode(Register code, |
| 4097 Register result) |
| 4098 : char_from_code_generator_(code, result) {} |
| 4099 |
| 4100 StringCharFromCodeGenerator* fast_case_generator() { |
| 4101 return &char_from_code_generator_; |
| 4102 } |
| 4103 |
| 4104 virtual void Generate() { |
| 4105 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 4106 char_from_code_generator_.GenerateSlow(masm(), call_helper); |
| 4107 } |
| 4108 |
| 4109 private: |
| 4110 StringCharFromCodeGenerator char_from_code_generator_; |
| 4111 }; |
| 4112 |
| 4113 |
| 4114 // Generates code for creating a one-char string from a char code. |
| 4115 void CodeGenerator::GenerateStringCharFromCode(ZoneList<Expression*>* args) { |
| 4116 Comment(masm_, "[ GenerateStringCharFromCode"); |
4027 ASSERT(args->length() == 1); | 4117 ASSERT(args->length() == 1); |
4028 | 4118 |
4029 Load(args->at(0)); | 4119 Load(args->at(0)); |
4030 | 4120 |
4031 Result code = frame_->Pop(); | 4121 Result code = frame_->Pop(); |
4032 code.ToRegister(); | 4122 code.ToRegister(); |
4033 ASSERT(code.is_valid()); | 4123 ASSERT(code.is_valid()); |
4034 | 4124 |
4035 // StringHelper::GenerateCharFromCode may do a runtime call. | |
4036 frame_->SpillAll(); | |
4037 | |
4038 Result result = allocator()->Allocate(); | 4125 Result result = allocator()->Allocate(); |
4039 ASSERT(result.is_valid()); | 4126 ASSERT(result.is_valid()); |
4040 Result scratch = allocator()->Allocate(); | |
4041 ASSERT(scratch.is_valid()); | |
4042 | 4127 |
4043 StringHelper::GenerateCharFromCode(masm_, | 4128 DeferredStringCharFromCode* deferred = new DeferredStringCharFromCode( |
4044 code.reg(), | 4129 code.reg(), result.reg()); |
4045 result.reg(), | 4130 deferred->fast_case_generator()->GenerateFast(masm_); |
4046 scratch.reg(), | 4131 deferred->BindExit(); |
4047 CALL_FUNCTION); | |
4048 frame_->Push(&result); | 4132 frame_->Push(&result); |
4049 } | 4133 } |
4050 | 4134 |
| 4135 |
| 4136 class DeferredStringCharAt : public DeferredCode { |
| 4137 public: |
| 4138 DeferredStringCharAt(Register object, |
| 4139 Register index, |
| 4140 Register scratch1, |
| 4141 Register scratch2, |
| 4142 Register result) |
| 4143 : result_(result), |
| 4144 char_at_generator_(object, |
| 4145 index, |
| 4146 scratch1, |
| 4147 scratch2, |
| 4148 result, |
| 4149 &need_conversion_, |
| 4150 &need_conversion_, |
| 4151 &index_out_of_range_, |
| 4152 STRING_ANY_NUMBER_INDEX) {} |
| 4153 |
| 4154 StringCharAtGenerator* fast_case_generator() { |
| 4155 return &char_at_generator_; |
| 4156 } |
| 4157 |
| 4158 virtual void Generate() { |
| 4159 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 4160 char_at_generator_.GenerateSlow(masm(), call_helper); |
| 4161 |
| 4162 __ bind(&need_conversion_); |
| 4163 // Move smi zero into the result register, which will trigger |
| 4164 // conversion. |
| 4165 __ Move(result_, Smi::FromInt(0)); |
| 4166 __ jmp(exit_label()); |
| 4167 |
| 4168 __ bind(&index_out_of_range_); |
| 4169 // When the index is out of range, the spec requires us to return |
| 4170 // the empty string. |
| 4171 __ LoadRoot(result_, Heap::kEmptyStringRootIndex); |
| 4172 __ jmp(exit_label()); |
| 4173 } |
| 4174 |
| 4175 private: |
| 4176 Register result_; |
| 4177 |
| 4178 Label need_conversion_; |
| 4179 Label index_out_of_range_; |
| 4180 |
| 4181 StringCharAtGenerator char_at_generator_; |
| 4182 }; |
| 4183 |
| 4184 |
| 4185 // This generates code that performs a String.prototype.charAt() call |
| 4186 // or returns a smi in order to trigger conversion. |
| 4187 void CodeGenerator::GenerateStringCharAt(ZoneList<Expression*>* args) { |
| 4188 Comment(masm_, "[ GenerateStringCharAt"); |
| 4189 ASSERT(args->length() == 2); |
| 4190 |
| 4191 Load(args->at(0)); |
| 4192 Load(args->at(1)); |
| 4193 Result index = frame_->Pop(); |
| 4194 Result object = frame_->Pop(); |
| 4195 object.ToRegister(); |
| 4196 index.ToRegister(); |
| 4197 // We might mutate the object register. |
| 4198 frame_->Spill(object.reg()); |
| 4199 |
| 4200 // We need three extra registers. |
| 4201 Result result = allocator()->Allocate(); |
| 4202 ASSERT(result.is_valid()); |
| 4203 Result scratch1 = allocator()->Allocate(); |
| 4204 ASSERT(scratch1.is_valid()); |
| 4205 Result scratch2 = allocator()->Allocate(); |
| 4206 ASSERT(scratch2.is_valid()); |
| 4207 |
| 4208 DeferredStringCharAt* deferred = |
| 4209 new DeferredStringCharAt(object.reg(), |
| 4210 index.reg(), |
| 4211 scratch1.reg(), |
| 4212 scratch2.reg(), |
| 4213 result.reg()); |
| 4214 deferred->fast_case_generator()->GenerateFast(masm_); |
| 4215 deferred->BindExit(); |
| 4216 frame_->Push(&result); |
| 4217 } |
| 4218 |
4051 | 4219 |
4052 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 4220 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
4053 ASSERT(args->length() == 1); | 4221 ASSERT(args->length() == 1); |
4054 Load(args->at(0)); | 4222 Load(args->at(0)); |
4055 Result value = frame_->Pop(); | 4223 Result value = frame_->Pop(); |
4056 value.ToRegister(); | 4224 value.ToRegister(); |
4057 ASSERT(value.is_valid()); | 4225 ASSERT(value.is_valid()); |
4058 Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); | 4226 Condition positive_smi = masm_->CheckPositiveSmi(value.reg()); |
4059 value.Unuse(); | 4227 value.Unuse(); |
4060 destination()->Split(positive_smi); | 4228 destination()->Split(positive_smi); |
(...skipping 6594 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10655 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 10823 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
10656 "CompareStub_%s%s%s%s", | 10824 "CompareStub_%s%s%s%s", |
10657 cc_name, | 10825 cc_name, |
10658 strict_name, | 10826 strict_name, |
10659 never_nan_nan_name, | 10827 never_nan_nan_name, |
10660 include_number_compare_name); | 10828 include_number_compare_name); |
10661 return name_; | 10829 return name_; |
10662 } | 10830 } |
10663 | 10831 |
10664 | 10832 |
10665 void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, | 10833 // ------------------------------------------------------------------------- |
10666 Register object, | 10834 // StringCharCodeAtGenerator |
10667 Register index, | 10835 |
10668 Register scratch, | 10836 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
10669 Register result, | 10837 Label flat_string; |
10670 Label* receiver_not_string, | |
10671 Label* index_not_smi, | |
10672 Label* index_out_of_range, | |
10673 Label* slow_case) { | |
10674 Label not_a_flat_string; | |
10675 Label try_again_with_new_string; | |
10676 Label ascii_string; | 10838 Label ascii_string; |
10677 Label got_char_code; | 10839 Label got_char_code; |
10678 | 10840 |
10679 // If the receiver is a smi trigger the non-string case. | 10841 // If the receiver is a smi trigger the non-string case. |
10680 __ JumpIfSmi(object, receiver_not_string); | 10842 __ JumpIfSmi(object_, receiver_not_string_); |
10681 | 10843 |
10682 // Fetch the instance type of the receiver into result register. | 10844 // Fetch the instance type of the receiver into result register. |
10683 __ movq(result, FieldOperand(object, HeapObject::kMapOffset)); | 10845 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
10684 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); | 10846 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
10685 // If the receiver is not a string trigger the non-string case. | 10847 // If the receiver is not a string trigger the non-string case. |
10686 __ testb(result, Immediate(kIsNotStringMask)); | 10848 __ testb(result_, Immediate(kIsNotStringMask)); |
10687 __ j(not_zero, receiver_not_string); | 10849 __ j(not_zero, receiver_not_string_); |
10688 | 10850 |
10689 // If the index is non-smi trigger the non-smi case. | 10851 // If the index is non-smi trigger the non-smi case. |
10690 __ JumpIfNotSmi(index, index_not_smi); | 10852 __ JumpIfNotSmi(index_, &index_not_smi_); |
| 10853 |
| 10854 // Put smi-tagged index into scratch register. |
| 10855 __ movq(scratch_, index_); |
| 10856 __ bind(&got_smi_index_); |
10691 | 10857 |
10692 // Check for index out of range. | 10858 // Check for index out of range. |
10693 __ SmiCompare(index, FieldOperand(object, String::kLengthOffset)); | 10859 __ SmiCompare(scratch_, FieldOperand(object_, String::kLengthOffset)); |
10694 __ j(above_equal, index_out_of_range); | 10860 __ j(above_equal, index_out_of_range_); |
10695 | |
10696 __ bind(&try_again_with_new_string); | |
10697 // ----------- S t a t e ------------- | |
10698 // -- object : string to access | |
10699 // -- result : instance type of the string | |
10700 // -- scratch : non-negative index < length | |
10701 // ----------------------------------- | |
10702 | 10861 |
10703 // We need special handling for non-flat strings. | 10862 // We need special handling for non-flat strings. |
10704 ASSERT_EQ(0, kSeqStringTag); | 10863 ASSERT(kSeqStringTag == 0); |
10705 __ testb(result, Immediate(kStringRepresentationMask)); | 10864 __ testb(result_, Immediate(kStringRepresentationMask)); |
10706 __ j(not_zero, ¬_a_flat_string); | 10865 __ j(zero, &flat_string); |
10707 | 10866 |
10708 // Put untagged index into scratch register. | 10867 // Handle non-flat strings. |
10709 __ SmiToInteger32(scratch, index); | 10868 __ testb(result_, Immediate(kIsConsStringMask)); |
| 10869 __ j(zero, &call_runtime_); |
| 10870 |
| 10871 // ConsString. |
| 10872 // Check whether the right hand side is the empty string (i.e. if |
| 10873 // this is really a flat string in a cons string). If that is not |
| 10874 // the case we would rather go to the runtime system now to flatten |
| 10875 // the string. |
| 10876 __ CompareRoot(FieldOperand(object_, ConsString::kSecondOffset), |
| 10877 Heap::kEmptyStringRootIndex); |
| 10878 __ j(not_equal, &call_runtime_); |
| 10879 // Get the first of the two strings and load its instance type. |
| 10880 __ movq(object_, FieldOperand(object_, ConsString::kFirstOffset)); |
| 10881 __ movq(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 10882 __ movzxbl(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 10883 // If the first cons component is also non-flat, then go to runtime. |
| 10884 ASSERT(kSeqStringTag == 0); |
| 10885 __ testb(result_, Immediate(kStringRepresentationMask)); |
| 10886 __ j(not_zero, &call_runtime_); |
10710 | 10887 |
10711 // Check for 1-byte or 2-byte string. | 10888 // Check for 1-byte or 2-byte string. |
10712 ASSERT_EQ(0, kTwoByteStringTag); | 10889 __ bind(&flat_string); |
10713 __ testb(result, Immediate(kStringEncodingMask)); | 10890 ASSERT(kAsciiStringTag != 0); |
| 10891 __ testb(result_, Immediate(kStringEncodingMask)); |
10714 __ j(not_zero, &ascii_string); | 10892 __ j(not_zero, &ascii_string); |
10715 | 10893 |
10716 // 2-byte string. | 10894 // 2-byte string. |
10717 // Load the 2-byte character code into the result register. | 10895 // Load the 2-byte character code into the result register. |
10718 __ movzxwl(result, FieldOperand(object, | 10896 __ SmiToInteger32(scratch_, scratch_); |
10719 scratch, | 10897 __ movzxwl(result_, FieldOperand(object_, |
10720 times_2, | 10898 scratch_, times_2, |
10721 SeqTwoByteString::kHeaderSize)); | 10899 SeqTwoByteString::kHeaderSize)); |
10722 __ jmp(&got_char_code); | 10900 __ jmp(&got_char_code); |
10723 | 10901 |
10724 // Handle non-flat strings. | |
10725 __ bind(¬_a_flat_string); | |
10726 __ and_(result, Immediate(kStringRepresentationMask)); | |
10727 __ cmpb(result, Immediate(kConsStringTag)); | |
10728 __ j(not_equal, slow_case); | |
10729 | |
10730 // ConsString. | |
10731 // Check that the right hand side is the empty string (ie if this is really a | |
10732 // flat string in a cons string). If that is not the case we would rather go | |
10733 // to the runtime system now, to flatten the string. | |
10734 __ movq(result, FieldOperand(object, ConsString::kSecondOffset)); | |
10735 __ CompareRoot(result, Heap::kEmptyStringRootIndex); | |
10736 __ j(not_equal, slow_case); | |
10737 // Get the first of the two strings and load its instance type. | |
10738 __ movq(object, FieldOperand(object, ConsString::kFirstOffset)); | |
10739 __ movq(result, FieldOperand(object, HeapObject::kMapOffset)); | |
10740 __ movzxbl(result, FieldOperand(result, Map::kInstanceTypeOffset)); | |
10741 __ jmp(&try_again_with_new_string); | |
10742 | |
10743 // ASCII string. | 10902 // ASCII string. |
| 10903 // Load the byte into the result register. |
10744 __ bind(&ascii_string); | 10904 __ bind(&ascii_string); |
10745 // Load the byte into the result register. | 10905 __ SmiToInteger32(scratch_, scratch_); |
10746 __ movzxbl(result, FieldOperand(object, | 10906 __ movzxbl(result_, FieldOperand(object_, |
10747 scratch, | 10907 scratch_, times_1, |
10748 times_1, | 10908 SeqAsciiString::kHeaderSize)); |
10749 SeqAsciiString::kHeaderSize)); | |
10750 __ bind(&got_char_code); | 10909 __ bind(&got_char_code); |
10751 __ Integer32ToSmi(result, result); | 10910 __ Integer32ToSmi(result_, result_); |
| 10911 __ bind(&exit_); |
10752 } | 10912 } |
10753 | 10913 |
10754 | 10914 |
10755 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, | 10915 void StringCharCodeAtGenerator::GenerateSlow( |
10756 Register code, | 10916 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
10757 Register result, | 10917 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
10758 Register scratch, | |
10759 InvokeFlag flag) { | |
10760 ASSERT(!code.is(result)); | |
10761 | 10918 |
10762 Label slow_case; | 10919 // Index is not a smi. |
10763 Label exit; | 10920 __ bind(&index_not_smi_); |
| 10921 // If index is a heap number, try converting it to an integer. |
| 10922 __ CheckMap(index_, Factory::heap_number_map(), index_not_number_, true); |
| 10923 call_helper.BeforeCall(masm); |
| 10924 __ push(object_); |
| 10925 __ push(index_); |
| 10926 __ push(result_); |
| 10927 __ push(index_); // Consumed by runtime conversion function. |
| 10928 if (index_flags_ == STRING_ANY_NUMBER_INDEX) { |
| 10929 // Strictly speaking, NumberToInteger should be called here, but |
| 10930 // our string lengths don't exceed 32 bits and using ToUint32 maps |
| 10931 // -0 to 0, which is what is required by the spec when accessing |
| 10932 // strings. |
| 10933 __ CallRuntime(Runtime::kNumberToJSUint32, 1); |
| 10934 } else { |
| 10935 ASSERT(index_flags_ == STRING_REQUIRE_ARRAY_INDEX); |
| 10936 // NumberToSmi discards numbers that are not exact integers. |
| 10937 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| 10938 } |
| 10939 if (!scratch_.is(rax)) { |
| 10940 // Save the conversion result before the pop instructions below |
| 10941 // have a chance to overwrite it. |
| 10942 __ movq(scratch_, rax); |
| 10943 } |
| 10944 __ pop(result_); |
| 10945 __ pop(index_); |
| 10946 __ pop(object_); |
| 10947 call_helper.AfterCall(masm); |
| 10948 // If index is still not a smi, it must be out of range. |
| 10949 __ JumpIfNotSmi(scratch_, index_out_of_range_); |
| 10950 // Otherwise, return to the fast path. |
| 10951 __ jmp(&got_smi_index_); |
10764 | 10952 |
10765 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 10953 // Call runtime. We get here when the receiver is a string and the |
10766 __ JumpIfNotSmi(code, &slow_case); | 10954 // index is a number, but the code of getting the actual character |
10767 __ SmiToInteger32(scratch, code); | 10955 // is too complex (e.g., when the string needs to be flattened). |
10768 __ cmpl(scratch, Immediate(String::kMaxAsciiCharCode)); | 10956 __ bind(&call_runtime_); |
10769 __ j(above, &slow_case); | 10957 call_helper.BeforeCall(masm); |
| 10958 __ push(object_); |
| 10959 __ push(index_); |
| 10960 __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
| 10961 if (!result_.is(rax)) { |
| 10962 __ movq(result_, rax); |
| 10963 } |
| 10964 call_helper.AfterCall(masm); |
| 10965 __ jmp(&exit_); |
10770 | 10966 |
10771 __ Move(result, Factory::single_character_string_cache()); | 10967 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); |
10772 __ movq(result, FieldOperand(result, | |
10773 scratch, | |
10774 times_pointer_size, | |
10775 FixedArray::kHeaderSize)); | |
10776 | |
10777 __ CompareRoot(result, Heap::kUndefinedValueRootIndex); | |
10778 __ j(equal, &slow_case); | |
10779 __ jmp(&exit); | |
10780 | |
10781 __ bind(&slow_case); | |
10782 if (flag == CALL_FUNCTION) { | |
10783 __ push(code); | |
10784 __ CallRuntime(Runtime::kCharFromCode, 1); | |
10785 if (!result.is(rax)) { | |
10786 __ movq(result, rax); | |
10787 } | |
10788 } else { | |
10789 ASSERT(flag == JUMP_FUNCTION); | |
10790 ASSERT(result.is(rax)); | |
10791 __ pop(rax); // Save return address. | |
10792 __ push(code); | |
10793 __ push(rax); // Restore return address. | |
10794 __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); | |
10795 } | |
10796 | |
10797 __ bind(&exit); | |
10798 if (flag == JUMP_FUNCTION) { | |
10799 ASSERT(result.is(rax)); | |
10800 __ ret(0); | |
10801 } | |
10802 } | 10968 } |
10803 | 10969 |
10804 | 10970 |
| 10971 // ------------------------------------------------------------------------- |
| 10972 // StringCharFromCodeGenerator |
| 10973 |
| 10974 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
| 10975 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 10976 __ JumpIfNotSmi(code_, &slow_case_); |
| 10977 __ SmiCompare(code_, Smi::FromInt(String::kMaxAsciiCharCode)); |
| 10978 __ j(above, &slow_case_); |
| 10979 |
| 10980 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
| 10981 SmiIndex index = masm->SmiToIndex(kScratchRegister, code_, kPointerSizeLog2); |
| 10982 __ movq(result_, FieldOperand(result_, index.reg, index.scale, |
| 10983 FixedArray::kHeaderSize)); |
| 10984 __ CompareRoot(result_, Heap::kUndefinedValueRootIndex); |
| 10985 __ j(equal, &slow_case_); |
| 10986 __ bind(&exit_); |
| 10987 } |
| 10988 |
| 10989 |
| 10990 void StringCharFromCodeGenerator::GenerateSlow( |
| 10991 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 10992 __ Abort("Unexpected fallthrough to CharFromCode slow case"); |
| 10993 |
| 10994 __ bind(&slow_case_); |
| 10995 call_helper.BeforeCall(masm); |
| 10996 __ push(code_); |
| 10997 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 10998 if (!result_.is(rax)) { |
| 10999 __ movq(result_, rax); |
| 11000 } |
| 11001 call_helper.AfterCall(masm); |
| 11002 __ jmp(&exit_); |
| 11003 |
| 11004 __ Abort("Unexpected fallthrough from CharFromCode slow case"); |
| 11005 } |
| 11006 |
| 11007 |
| 11008 // ------------------------------------------------------------------------- |
| 11009 // StringCharAtGenerator |
| 11010 |
| 11011 void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 11012 char_code_at_generator_.GenerateFast(masm); |
| 11013 char_from_code_generator_.GenerateFast(masm); |
| 11014 } |
| 11015 |
| 11016 |
| 11017 void StringCharAtGenerator::GenerateSlow( |
| 11018 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 11019 char_code_at_generator_.GenerateSlow(masm, call_helper); |
| 11020 char_from_code_generator_.GenerateSlow(masm, call_helper); |
| 11021 } |
| 11022 |
| 11023 |
10805 void StringAddStub::Generate(MacroAssembler* masm) { | 11024 void StringAddStub::Generate(MacroAssembler* masm) { |
10806 Label string_add_runtime; | 11025 Label string_add_runtime; |
10807 | 11026 |
10808 // Load the two arguments. | 11027 // Load the two arguments. |
10809 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. | 11028 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument. |
10810 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. | 11029 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument. |
10811 | 11030 |
10812 // Make sure that both arguments are strings if not known in advance. | 11031 // Make sure that both arguments are strings if not known in advance. |
10813 if (string_check_) { | 11032 if (string_check_) { |
10814 Condition is_smi; | 11033 Condition is_smi; |
(...skipping 835 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11650 } | 11869 } |
11651 | 11870 |
11652 #endif | 11871 #endif |
11653 | 11872 |
11654 | 11873 |
11655 #undef __ | 11874 #undef __ |
11656 | 11875 |
11657 } } // namespace v8::internal | 11876 } } // namespace v8::internal |
11658 | 11877 |
11659 #endif // V8_TARGET_ARCH_X64 | 11878 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |