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

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

Issue 2087009: Custom call IC-s for String.prototype.{charAt,charCodeAt}. (Closed)
Patch Set: ARM port. Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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, &not_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(&not_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
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
OLDNEW
« no previous file with comments | « src/arm/codegen-arm.h ('k') | src/arm/full-codegen-arm.cc » ('j') | src/codegen.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698