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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 #include "register-allocator-inl.h" | 42 #include "register-allocator-inl.h" |
43 #include "runtime.h" | 43 #include "runtime.h" |
44 #include "scopes.h" | 44 #include "scopes.h" |
45 #include "virtual-frame-inl.h" | 45 #include "virtual-frame-inl.h" |
46 #include "virtual-frame-arm-inl.h" | 46 #include "virtual-frame-arm-inl.h" |
47 | 47 |
48 namespace v8 { | 48 namespace v8 { |
49 namespace internal { | 49 namespace internal { |
50 | 50 |
51 | 51 |
52 #define __ ACCESS_MASM(masm_) | |
53 | |
54 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 52 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
55 Label* slow, | 53 Label* slow, |
56 Condition cc, | 54 Condition cc, |
57 bool never_nan_nan); | 55 bool never_nan_nan); |
58 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 56 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
59 Label* lhs_not_nan, | 57 Label* lhs_not_nan, |
60 Label* slow, | 58 Label* slow, |
61 bool strict); | 59 bool strict); |
62 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); | 60 static void EmitTwoNonNanDoubleComparison(MacroAssembler* masm, Condition cc); |
63 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); | 61 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm); |
64 static void MultiplyByKnownInt(MacroAssembler* masm, | 62 static void MultiplyByKnownInt(MacroAssembler* masm, |
65 Register source, | 63 Register source, |
66 Register destination, | 64 Register destination, |
67 int known_int); | 65 int known_int); |
68 static bool IsEasyToMultiplyBy(int x); | 66 static bool IsEasyToMultiplyBy(int x); |
69 | 67 |
70 | 68 |
| 69 #define __ ACCESS_MASM(masm) |
71 | 70 |
72 // ------------------------------------------------------------------------- | 71 // ------------------------------------------------------------------------- |
73 // Platform-specific DeferredCode functions. | 72 // Platform-specific FrameRegisterState functions. |
74 | 73 |
75 void DeferredCode::SaveRegisters() { | 74 void FrameRegisterState::Save(MacroAssembler* masm) const { |
76 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { | 75 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) { |
77 int action = registers_[i]; | 76 int action = registers_[i]; |
78 if (action == kPush) { | 77 if (action == kPush) { |
79 __ push(RegisterAllocator::ToRegister(i)); | 78 __ push(RegisterAllocator::ToRegister(i)); |
80 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { | 79 } else if (action != kIgnore && (action & kSyncedFlag) == 0) { |
81 __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); | 80 __ str(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); |
82 } | 81 } |
83 } | 82 } |
84 } | 83 } |
85 | 84 |
86 | 85 |
87 void DeferredCode::RestoreRegisters() { | 86 void FrameRegisterState::Restore(MacroAssembler* masm) const { |
88 // Restore registers in reverse order due to the stack. | 87 // Restore registers in reverse order due to the stack. |
89 for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) { | 88 for (int i = RegisterAllocator::kNumRegisters - 1; i >= 0; i--) { |
90 int action = registers_[i]; | 89 int action = registers_[i]; |
91 if (action == kPush) { | 90 if (action == kPush) { |
92 __ pop(RegisterAllocator::ToRegister(i)); | 91 __ pop(RegisterAllocator::ToRegister(i)); |
93 } else if (action != kIgnore) { | 92 } else if (action != kIgnore) { |
94 action &= ~kSyncedFlag; | 93 action &= ~kSyncedFlag; |
95 __ ldr(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); | 94 __ ldr(RegisterAllocator::ToRegister(i), MemOperand(fp, action)); |
96 } | 95 } |
97 } | 96 } |
98 } | 97 } |
99 | 98 |
100 | 99 |
| 100 #undef __ |
| 101 #define __ ACCESS_MASM(masm_) |
| 102 |
| 103 // ------------------------------------------------------------------------- |
| 104 // Platform-specific DeferredCode functions. |
| 105 |
| 106 void DeferredCode::SaveRegisters() { |
| 107 frame_state_.Save(masm_); |
| 108 } |
| 109 |
| 110 |
| 111 void DeferredCode::RestoreRegisters() { |
| 112 frame_state_.Restore(masm_); |
| 113 } |
| 114 |
| 115 |
| 116 // ------------------------------------------------------------------------- |
| 117 // Platform-specific RuntimeCallHelper functions. |
| 118 |
| 119 void VirtualFrameRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
| 120 frame_state_->Save(masm); |
| 121 } |
| 122 |
| 123 |
| 124 void VirtualFrameRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
| 125 frame_state_->Restore(masm); |
| 126 } |
| 127 |
| 128 |
| 129 void ICRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { |
| 130 masm->EnterInternalFrame(); |
| 131 } |
| 132 |
| 133 |
| 134 void ICRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { |
| 135 masm->LeaveInternalFrame(); |
| 136 } |
| 137 |
| 138 |
101 // ------------------------------------------------------------------------- | 139 // ------------------------------------------------------------------------- |
102 // CodeGenState implementation. | 140 // CodeGenState implementation. |
103 | 141 |
104 CodeGenState::CodeGenState(CodeGenerator* owner) | 142 CodeGenState::CodeGenState(CodeGenerator* owner) |
105 : owner_(owner), | 143 : owner_(owner), |
106 true_target_(NULL), | 144 true_target_(NULL), |
107 false_target_(NULL), | 145 false_target_(NULL), |
108 previous_(NULL) { | 146 previous_(NULL) { |
109 owner_->set_state(this); | 147 owner_->set_state(this); |
110 } | 148 } |
(...skipping 3977 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4088 | 4126 |
4089 // Generates the Math.sqrt method - currently just calls runtime. | 4127 // Generates the Math.sqrt method - currently just calls runtime. |
4090 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { | 4128 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { |
4091 ASSERT(args->length() == 1); | 4129 ASSERT(args->length() == 1); |
4092 Load(args->at(0)); | 4130 Load(args->at(0)); |
4093 frame_->CallRuntime(Runtime::kMath_sqrt, 1); | 4131 frame_->CallRuntime(Runtime::kMath_sqrt, 1); |
4094 frame_->EmitPush(r0); | 4132 frame_->EmitPush(r0); |
4095 } | 4133 } |
4096 | 4134 |
4097 | 4135 |
4098 // This generates code that performs a charCodeAt() call or returns | 4136 class DeferredStringCharCodeAt : public DeferredCode { |
4099 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 4137 public: |
4100 // It can handle flat, 8 and 16 bit characters and cons strings where the | 4138 DeferredStringCharCodeAt(Register object, |
4101 // answer is found in the left hand branch of the cons. The slow case will | 4139 Register index, |
4102 // flatten the string, which will ensure that the answer is in the left hand | 4140 Register scratch, |
4103 // side the next time around. | 4141 Register result) |
4104 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 4142 : result_(result), |
| 4143 char_code_at_generator_(object, |
| 4144 index, |
| 4145 scratch, |
| 4146 result, |
| 4147 &need_conversion_, |
| 4148 &need_conversion_, |
| 4149 &index_out_of_range_, |
| 4150 STRING_ANY_NUMBER_INDEX) {} |
| 4151 |
| 4152 StringCharCodeAtGenerator* fast_case_generator() { |
| 4153 return &char_code_at_generator_; |
| 4154 } |
| 4155 |
| 4156 virtual void Generate() { |
| 4157 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 4158 char_code_at_generator_.GenerateSlow(masm(), call_helper); |
| 4159 |
| 4160 __ bind(&need_conversion_); |
| 4161 // Move the undefined value into the result register, which will |
| 4162 // trigger conversion. |
| 4163 __ LoadRoot(result_, Heap::kUndefinedValueRootIndex); |
| 4164 __ jmp(exit_label()); |
| 4165 |
| 4166 __ bind(&index_out_of_range_); |
| 4167 // When the index is out of range, the spec requires us to return |
| 4168 // NaN. |
| 4169 __ LoadRoot(result_, Heap::kNanValueRootIndex); |
| 4170 __ jmp(exit_label()); |
| 4171 } |
| 4172 |
| 4173 private: |
| 4174 Register result_; |
| 4175 |
| 4176 Label need_conversion_; |
| 4177 Label index_out_of_range_; |
| 4178 |
| 4179 StringCharCodeAtGenerator char_code_at_generator_; |
| 4180 }; |
| 4181 |
| 4182 |
| 4183 // This generates code that performs a String.prototype.charCodeAt() call |
| 4184 // or returns a smi in order to trigger conversion. |
| 4185 void CodeGenerator::GenerateStringCharCodeAt(ZoneList<Expression*>* args) { |
4105 VirtualFrame::SpilledScope spilled_scope(frame_); | 4186 VirtualFrame::SpilledScope spilled_scope(frame_); |
| 4187 Comment(masm_, "[ GenerateStringCharCodeAt"); |
4106 ASSERT(args->length() == 2); | 4188 ASSERT(args->length() == 2); |
4107 Comment(masm_, "[ GenerateFastCharCodeAt"); | |
4108 | 4189 |
4109 LoadAndSpill(args->at(0)); | 4190 LoadAndSpill(args->at(0)); |
4110 LoadAndSpill(args->at(1)); | 4191 LoadAndSpill(args->at(1)); |
4111 frame_->EmitPop(r1); // Index. | 4192 |
4112 frame_->EmitPop(r2); // String. | 4193 Register index = r1; |
4113 | 4194 Register object = r2; |
4114 Label slow_case; | 4195 |
4115 Label exit; | 4196 frame_->EmitPop(r1); |
4116 StringHelper::GenerateFastCharCodeAt(masm_, | 4197 frame_->EmitPop(r2); |
4117 r2, | 4198 |
4118 r1, | 4199 // We need two extra registers. |
4119 r3, | 4200 Register scratch = r3; |
4120 r0, | 4201 Register result = r0; |
4121 &slow_case, | 4202 |
4122 &slow_case, | 4203 DeferredStringCharCodeAt* deferred = |
4123 &slow_case, | 4204 new DeferredStringCharCodeAt(object, |
4124 &slow_case); | 4205 index, |
4125 __ jmp(&exit); | 4206 scratch, |
4126 | 4207 result); |
4127 __ bind(&slow_case); | 4208 deferred->fast_case_generator()->GenerateFast(masm_); |
4128 // Move the undefined value into the result register, which will | 4209 deferred->BindExit(); |
4129 // trigger the slow case. | 4210 frame_->EmitPush(result); |
4130 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 4211 } |
4131 | 4212 |
4132 __ bind(&exit); | 4213 |
4133 frame_->EmitPush(r0); | 4214 class DeferredStringCharFromCode : public DeferredCode { |
4134 } | 4215 public: |
4135 | 4216 DeferredStringCharFromCode(Register code, |
4136 | 4217 Register result) |
4137 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { | 4218 : char_from_code_generator_(code, result) {} |
4138 Comment(masm_, "[ GenerateCharFromCode"); | 4219 |
| 4220 StringCharFromCodeGenerator* fast_case_generator() { |
| 4221 return &char_from_code_generator_; |
| 4222 } |
| 4223 |
| 4224 virtual void Generate() { |
| 4225 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 4226 char_from_code_generator_.GenerateSlow(masm(), call_helper); |
| 4227 } |
| 4228 |
| 4229 private: |
| 4230 StringCharFromCodeGenerator char_from_code_generator_; |
| 4231 }; |
| 4232 |
| 4233 |
| 4234 // Generates code for creating a one-char string from a char code. |
| 4235 void CodeGenerator::GenerateStringCharFromCode(ZoneList<Expression*>* args) { |
| 4236 VirtualFrame::SpilledScope spilled_scope(frame_); |
| 4237 Comment(masm_, "[ GenerateStringCharFromCode"); |
4139 ASSERT(args->length() == 1); | 4238 ASSERT(args->length() == 1); |
4140 | 4239 |
| 4240 LoadAndSpill(args->at(0)); |
| 4241 |
4141 Register code = r1; | 4242 Register code = r1; |
4142 Register scratch = ip; | |
4143 Register result = r0; | 4243 Register result = r0; |
4144 | 4244 |
| 4245 frame_->EmitPop(code); |
| 4246 |
| 4247 DeferredStringCharFromCode* deferred = new DeferredStringCharFromCode( |
| 4248 code, result); |
| 4249 deferred->fast_case_generator()->GenerateFast(masm_); |
| 4250 deferred->BindExit(); |
| 4251 frame_->EmitPush(result); |
| 4252 } |
| 4253 |
| 4254 |
| 4255 class DeferredStringCharAt : public DeferredCode { |
| 4256 public: |
| 4257 DeferredStringCharAt(Register object, |
| 4258 Register index, |
| 4259 Register scratch1, |
| 4260 Register scratch2, |
| 4261 Register result) |
| 4262 : result_(result), |
| 4263 char_at_generator_(object, |
| 4264 index, |
| 4265 scratch1, |
| 4266 scratch2, |
| 4267 result, |
| 4268 &need_conversion_, |
| 4269 &need_conversion_, |
| 4270 &index_out_of_range_, |
| 4271 STRING_ANY_NUMBER_INDEX) {} |
| 4272 |
| 4273 StringCharAtGenerator* fast_case_generator() { |
| 4274 return &char_at_generator_; |
| 4275 } |
| 4276 |
| 4277 virtual void Generate() { |
| 4278 VirtualFrameRuntimeCallHelper call_helper(frame_state()); |
| 4279 char_at_generator_.GenerateSlow(masm(), call_helper); |
| 4280 |
| 4281 __ bind(&need_conversion_); |
| 4282 // Move smi zero into the result register, which will trigger |
| 4283 // conversion. |
| 4284 __ mov(result_, Operand(Smi::FromInt(0))); |
| 4285 __ jmp(exit_label()); |
| 4286 |
| 4287 __ bind(&index_out_of_range_); |
| 4288 // When the index is out of range, the spec requires us to return |
| 4289 // the empty string. |
| 4290 __ LoadRoot(result_, Heap::kEmptyStringRootIndex); |
| 4291 __ jmp(exit_label()); |
| 4292 } |
| 4293 |
| 4294 private: |
| 4295 Register result_; |
| 4296 |
| 4297 Label need_conversion_; |
| 4298 Label index_out_of_range_; |
| 4299 |
| 4300 StringCharAtGenerator char_at_generator_; |
| 4301 }; |
| 4302 |
| 4303 |
| 4304 // This generates code that performs a String.prototype.charAt() call |
| 4305 // or returns a smi in order to trigger conversion. |
| 4306 void CodeGenerator::GenerateStringCharAt(ZoneList<Expression*>* args) { |
| 4307 VirtualFrame::SpilledScope spilled_scope(frame_); |
| 4308 Comment(masm_, "[ GenerateStringCharAt"); |
| 4309 ASSERT(args->length() == 2); |
| 4310 |
4145 LoadAndSpill(args->at(0)); | 4311 LoadAndSpill(args->at(0)); |
4146 frame_->EmitPop(code); | 4312 LoadAndSpill(args->at(1)); |
4147 | 4313 |
4148 StringHelper::GenerateCharFromCode(masm_, | 4314 Register index = r1; |
4149 code, | 4315 Register object = r2; |
4150 scratch, | 4316 |
4151 result, | 4317 frame_->EmitPop(r1); |
4152 CALL_FUNCTION); | 4318 frame_->EmitPop(r2); |
| 4319 |
| 4320 // We need three extra registers. |
| 4321 Register scratch1 = r3; |
| 4322 Register scratch2 = r4; |
| 4323 Register result = r0; |
| 4324 |
| 4325 DeferredStringCharAt* deferred = |
| 4326 new DeferredStringCharAt(object, |
| 4327 index, |
| 4328 scratch1, |
| 4329 scratch2, |
| 4330 result); |
| 4331 deferred->fast_case_generator()->GenerateFast(masm_); |
| 4332 deferred->BindExit(); |
4153 frame_->EmitPush(result); | 4333 frame_->EmitPush(result); |
4154 } | 4334 } |
4155 | 4335 |
4156 | 4336 |
4157 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 4337 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
4158 VirtualFrame::SpilledScope spilled_scope(frame_); | 4338 VirtualFrame::SpilledScope spilled_scope(frame_); |
4159 ASSERT(args->length() == 1); | 4339 ASSERT(args->length() == 1); |
4160 LoadAndSpill(args->at(0)); | 4340 LoadAndSpill(args->at(0)); |
4161 JumpTarget answer; | 4341 JumpTarget answer; |
4162 // We need the CC bits to come out as not_equal in the case where the | 4342 // We need the CC bits to come out as not_equal in the case where the |
(...skipping 4842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9005 // stubs the never NaN NaN condition is only taken into account if the | 9185 // stubs the never NaN NaN condition is only taken into account if the |
9006 // condition is equals. | 9186 // condition is equals. |
9007 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 13)); | 9187 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 13)); |
9008 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) | 9188 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) |
9009 | StrictField::encode(strict_) | 9189 | StrictField::encode(strict_) |
9010 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) | 9190 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) |
9011 | IncludeNumberCompareField::encode(include_number_compare_); | 9191 | IncludeNumberCompareField::encode(include_number_compare_); |
9012 } | 9192 } |
9013 | 9193 |
9014 | 9194 |
9015 void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, | 9195 // StringCharCodeAtGenerator |
9016 Register object, | 9196 |
9017 Register index, | 9197 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
9018 Register scratch, | 9198 Label flat_string; |
9019 Register result, | |
9020 Label* receiver_not_string, | |
9021 Label* index_not_smi, | |
9022 Label* index_out_of_range, | |
9023 Label* slow_case) { | |
9024 Label not_a_flat_string; | |
9025 Label try_again_with_new_string; | |
9026 Label ascii_string; | 9199 Label ascii_string; |
9027 Label got_char_code; | 9200 Label got_char_code; |
9028 | 9201 |
9029 // If the receiver is a smi trigger the non-string case. | 9202 // If the receiver is a smi trigger the non-string case. |
9030 __ BranchOnSmi(object, receiver_not_string); | 9203 __ BranchOnSmi(object_, receiver_not_string_); |
9031 | 9204 |
9032 // Fetch the instance type of the receiver into result register. | 9205 // Fetch the instance type of the receiver into result register. |
9033 __ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset)); | 9206 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
9034 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 9207 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
9035 // If the receiver is not a string trigger the non-string case. | 9208 // If the receiver is not a string trigger the non-string case. |
9036 __ tst(result, Operand(kIsNotStringMask)); | 9209 __ tst(result_, Operand(kIsNotStringMask)); |
9037 __ b(ne, receiver_not_string); | 9210 __ b(ne, receiver_not_string_); |
9038 | 9211 |
9039 // If the index is non-smi trigger the non-smi case. | 9212 // If the index is non-smi trigger the non-smi case. |
9040 __ BranchOnNotSmi(index, index_not_smi); | 9213 __ BranchOnNotSmi(index_, &index_not_smi_); |
| 9214 |
| 9215 // Put smi-tagged index into scratch register. |
| 9216 __ mov(scratch_, index_); |
| 9217 __ bind(&got_smi_index_); |
9041 | 9218 |
9042 // Check for index out of range. | 9219 // Check for index out of range. |
9043 __ ldr(scratch, FieldMemOperand(object, String::kLengthOffset)); | 9220 __ ldr(ip, FieldMemOperand(object_, String::kLengthOffset)); |
9044 // Now scratch has the length of the string. Compare with the index. | 9221 __ cmp(ip, Operand(scratch_)); |
9045 __ cmp(scratch, Operand(index)); | 9222 __ b(ls, index_out_of_range_); |
9046 __ b(ls, index_out_of_range); | |
9047 | |
9048 __ bind(&try_again_with_new_string); | |
9049 // ----------- S t a t e ------------- | |
9050 // -- object : string to access | |
9051 // -- result : instance type of the string | |
9052 // -- scratch : non-negative index < length | |
9053 // ----------------------------------- | |
9054 | 9223 |
9055 // We need special handling for non-flat strings. | 9224 // We need special handling for non-flat strings. |
9056 ASSERT_EQ(0, kSeqStringTag); | 9225 ASSERT(kSeqStringTag == 0); |
9057 __ tst(result, Operand(kStringRepresentationMask)); | 9226 __ tst(result_, Operand(kStringRepresentationMask)); |
9058 __ b(ne, ¬_a_flat_string); | 9227 __ b(eq, &flat_string); |
9059 | |
9060 // Check for 1-byte or 2-byte string. | |
9061 ASSERT_EQ(0, kTwoByteStringTag); | |
9062 __ tst(result, Operand(kStringEncodingMask)); | |
9063 __ b(ne, &ascii_string); | |
9064 | |
9065 // 2-byte string. We can add without shifting since the Smi tag size is the | |
9066 // log2 of the number of bytes in a two-byte character. | |
9067 ASSERT_EQ(1, kSmiTagSize); | |
9068 ASSERT_EQ(0, kSmiShiftSize); | |
9069 __ add(scratch, object, Operand(index)); | |
9070 __ ldrh(result, FieldMemOperand(scratch, SeqTwoByteString::kHeaderSize)); | |
9071 __ jmp(&got_char_code); | |
9072 | 9228 |
9073 // Handle non-flat strings. | 9229 // Handle non-flat strings. |
9074 __ bind(¬_a_flat_string); | 9230 __ tst(result_, Operand(kIsConsStringMask)); |
9075 __ and_(result, result, Operand(kStringRepresentationMask)); | 9231 __ b(eq, &call_runtime_); |
9076 __ cmp(result, Operand(kConsStringTag)); | |
9077 __ b(ne, slow_case); | |
9078 | 9232 |
9079 // ConsString. | 9233 // ConsString. |
9080 // Check whether the right hand side is the empty string (i.e. if | 9234 // Check whether the right hand side is the empty string (i.e. if |
9081 // this is really a flat string in a cons string). If that is not | 9235 // this is really a flat string in a cons string). If that is not |
9082 // the case we would rather go to the runtime system now to flatten | 9236 // the case we would rather go to the runtime system now to flatten |
9083 // the string. | 9237 // the string. |
9084 __ ldr(result, FieldMemOperand(object, ConsString::kSecondOffset)); | 9238 __ ldr(result_, FieldMemOperand(object_, ConsString::kSecondOffset)); |
9085 __ LoadRoot(scratch, Heap::kEmptyStringRootIndex); | 9239 __ LoadRoot(ip, Heap::kEmptyStringRootIndex); |
9086 __ cmp(result, Operand(scratch)); | 9240 __ cmp(result_, Operand(ip)); |
9087 __ b(ne, slow_case); | 9241 __ b(ne, &call_runtime_); |
| 9242 // Get the first of the two strings and load its instance type. |
| 9243 __ ldr(object_, FieldMemOperand(object_, ConsString::kFirstOffset)); |
| 9244 __ ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset)); |
| 9245 __ ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset)); |
| 9246 // If the first cons component is also non-flat, then go to runtime. |
| 9247 ASSERT(kSeqStringTag == 0); |
| 9248 __ tst(result_, Operand(kStringRepresentationMask)); |
| 9249 __ b(nz, &call_runtime_); |
9088 | 9250 |
9089 // Get the first of the two strings and load its instance type. | 9251 // Check for 1-byte or 2-byte string. |
9090 __ ldr(object, FieldMemOperand(object, ConsString::kFirstOffset)); | 9252 __ bind(&flat_string); |
9091 __ ldr(result, FieldMemOperand(object, HeapObject::kMapOffset)); | 9253 ASSERT(kAsciiStringTag != 0); |
9092 __ ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 9254 __ tst(result_, Operand(kStringEncodingMask)); |
9093 __ jmp(&try_again_with_new_string); | 9255 __ b(nz, &ascii_string); |
| 9256 |
| 9257 // 2-byte string. |
| 9258 // Load the 2-byte character code into the result register. We can |
| 9259 // add without shifting since the smi tag size is the log2 of the |
| 9260 // number of bytes in a two-byte character. |
| 9261 ASSERT(kSmiTag == 0 && kSmiTagSize == 1 && kSmiShiftSize == 0); |
| 9262 __ add(scratch_, object_, Operand(scratch_)); |
| 9263 __ ldrh(result_, FieldMemOperand(scratch_, SeqTwoByteString::kHeaderSize)); |
| 9264 __ jmp(&got_char_code); |
9094 | 9265 |
9095 // ASCII string. | 9266 // ASCII string. |
| 9267 // Load the byte into the result register. |
9096 __ bind(&ascii_string); | 9268 __ bind(&ascii_string); |
9097 __ add(scratch, object, Operand(index, LSR, kSmiTagSize)); | 9269 __ add(scratch_, object_, Operand(scratch_, LSR, kSmiTagSize)); |
9098 __ ldrb(result, FieldMemOperand(scratch, SeqAsciiString::kHeaderSize)); | 9270 __ ldrb(result_, FieldMemOperand(scratch_, SeqAsciiString::kHeaderSize)); |
9099 | 9271 |
9100 __ bind(&got_char_code); | 9272 __ bind(&got_char_code); |
9101 __ mov(result, Operand(result, LSL, kSmiTagSize)); | 9273 __ mov(result_, Operand(result_, LSL, kSmiTagSize)); |
| 9274 __ bind(&exit_); |
9102 } | 9275 } |
9103 | 9276 |
9104 | 9277 |
9105 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, | 9278 void StringCharCodeAtGenerator::GenerateSlow( |
9106 Register code, | 9279 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
9107 Register scratch, | 9280 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
9108 Register result, | |
9109 InvokeFlag flag) { | |
9110 ASSERT(!code.is(result)); | |
9111 | 9281 |
9112 Label slow_case; | 9282 // Index is not a smi. |
9113 Label exit; | 9283 __ bind(&index_not_smi_); |
| 9284 // If index is a heap number, try converting it to an integer. |
| 9285 __ CheckMap(index_, scratch_, |
| 9286 Factory::heap_number_map(), index_not_number_, true); |
| 9287 call_helper.BeforeCall(masm); |
| 9288 __ Push(object_, index_, result_); |
| 9289 __ push(index_); // Consumed by runtime conversion function. |
| 9290 if (index_flags_ == STRING_ANY_NUMBER_INDEX) { |
| 9291 // Strictly speaking, NumberToInteger should be called here, but |
| 9292 // our string lengths don't exceed 32 bits and using ToUint32 maps |
| 9293 // -0 to 0, which is what is required by the spec when accessing |
| 9294 // strings. |
| 9295 __ CallRuntime(Runtime::kNumberToJSUint32, 1); |
| 9296 } else { |
| 9297 ASSERT(index_flags_ == STRING_REQUIRE_ARRAY_INDEX); |
| 9298 // NumberToSmi discards numbers that are not exact integers. |
| 9299 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| 9300 } |
| 9301 if (!scratch_.is(r0)) { |
| 9302 // Save the conversion result before the pop instructions below |
| 9303 // have a chance to overwrite it. |
| 9304 __ mov(scratch_, r0); |
| 9305 } |
| 9306 __ pop(result_); |
| 9307 __ pop(index_); |
| 9308 __ pop(object_); |
| 9309 call_helper.AfterCall(masm); |
| 9310 // If index is still not a smi, it must be out of range. |
| 9311 __ BranchOnNotSmi(scratch_, index_out_of_range_); |
| 9312 // Otherwise, return to the fast path. |
| 9313 __ jmp(&got_smi_index_); |
9114 | 9314 |
| 9315 // Call runtime. We get here when the receiver is a string and the |
| 9316 // index is a number, but the code of getting the actual character |
| 9317 // is too complex (e.g., when the string needs to be flattened). |
| 9318 __ bind(&call_runtime_); |
| 9319 call_helper.BeforeCall(masm); |
| 9320 __ Push(object_, index_); |
| 9321 __ CallRuntime(Runtime::kStringCharCodeAt, 2); |
| 9322 if (!result_.is(r0)) { |
| 9323 __ mov(result_, r0); |
| 9324 } |
| 9325 call_helper.AfterCall(masm); |
| 9326 __ jmp(&exit_); |
| 9327 |
| 9328 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); |
| 9329 } |
| 9330 |
| 9331 |
| 9332 // ------------------------------------------------------------------------- |
| 9333 // StringCharFromCodeGenerator |
| 9334 |
| 9335 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
9115 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 9336 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
9116 ASSERT(kSmiTag == 0); | 9337 ASSERT(kSmiTag == 0); |
9117 ASSERT(kSmiShiftSize == 0); | 9338 ASSERT(kSmiShiftSize == 0); |
9118 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | 9339 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
9119 __ tst(code, Operand(kSmiTagMask | | 9340 __ tst(code_, |
9120 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | 9341 Operand(kSmiTagMask | |
9121 __ b(nz, &slow_case); | 9342 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 9343 __ b(nz, &slow_case_); |
9122 | 9344 |
| 9345 __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex); |
| 9346 // At this point code register contains smi tagged ascii char code. |
9123 ASSERT(kSmiTag == 0); | 9347 ASSERT(kSmiTag == 0); |
9124 __ mov(result, Operand(Factory::single_character_string_cache())); | 9348 __ add(result_, result_, Operand(code_, LSL, kPointerSizeLog2 - kSmiTagSize)); |
9125 __ add(result, result, Operand(code, LSL, kPointerSizeLog2 - kSmiTagSize)); | 9349 __ ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize)); |
9126 __ ldr(result, MemOperand(result, FixedArray::kHeaderSize - kHeapObjectTag)); | 9350 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
9127 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex); | 9351 __ cmp(result_, Operand(ip)); |
9128 __ cmp(result, scratch); | 9352 __ b(eq, &slow_case_); |
9129 __ b(eq, &slow_case); | 9353 __ bind(&exit_); |
9130 __ b(&exit); | |
9131 | |
9132 __ bind(&slow_case); | |
9133 if (flag == CALL_FUNCTION) { | |
9134 __ push(code); | |
9135 __ CallRuntime(Runtime::kCharFromCode, 1); | |
9136 if (!result.is(r0)) { | |
9137 __ mov(result, r0); | |
9138 } | |
9139 } else { | |
9140 ASSERT(flag == JUMP_FUNCTION); | |
9141 ASSERT(result.is(r0)); | |
9142 __ push(code); | |
9143 __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); | |
9144 } | |
9145 | |
9146 __ bind(&exit); | |
9147 if (flag == JUMP_FUNCTION) { | |
9148 ASSERT(result.is(r0)); | |
9149 __ Ret(); | |
9150 } | |
9151 } | 9354 } |
9152 | 9355 |
9153 | 9356 |
| 9357 void StringCharFromCodeGenerator::GenerateSlow( |
| 9358 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 9359 __ Abort("Unexpected fallthrough to CharFromCode slow case"); |
| 9360 |
| 9361 __ bind(&slow_case_); |
| 9362 call_helper.BeforeCall(masm); |
| 9363 __ push(code_); |
| 9364 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 9365 if (!result_.is(r0)) { |
| 9366 __ mov(result_, r0); |
| 9367 } |
| 9368 call_helper.AfterCall(masm); |
| 9369 __ jmp(&exit_); |
| 9370 |
| 9371 __ Abort("Unexpected fallthrough from CharFromCode slow case"); |
| 9372 } |
| 9373 |
| 9374 |
| 9375 // ------------------------------------------------------------------------- |
| 9376 // StringCharAtGenerator |
| 9377 |
| 9378 void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 9379 char_code_at_generator_.GenerateFast(masm); |
| 9380 char_from_code_generator_.GenerateFast(masm); |
| 9381 } |
| 9382 |
| 9383 |
| 9384 void StringCharAtGenerator::GenerateSlow( |
| 9385 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 9386 char_code_at_generator_.GenerateSlow(masm, call_helper); |
| 9387 char_from_code_generator_.GenerateSlow(masm, call_helper); |
| 9388 } |
| 9389 |
| 9390 |
9154 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | 9391 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
9155 Register dest, | 9392 Register dest, |
9156 Register src, | 9393 Register src, |
9157 Register count, | 9394 Register count, |
9158 Register scratch, | 9395 Register scratch, |
9159 bool ascii) { | 9396 bool ascii) { |
9160 Label loop; | 9397 Label loop; |
9161 Label done; | 9398 Label done; |
9162 // This loop just copies one character at a time, as it is only used for very | 9399 // This loop just copies one character at a time, as it is only used for very |
9163 // short strings. | 9400 // short strings. |
(...skipping 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10035 __ bind(&string_add_runtime); | 10272 __ bind(&string_add_runtime); |
10036 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 10273 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
10037 } | 10274 } |
10038 | 10275 |
10039 | 10276 |
10040 #undef __ | 10277 #undef __ |
10041 | 10278 |
10042 } } // namespace v8::internal | 10279 } } // namespace v8::internal |
10043 | 10280 |
10044 #endif // V8_TARGET_ARCH_ARM | 10281 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |