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 912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
923 // On entry lhs_ and rhs_ are the values to be compared. | 923 // On entry lhs_ and rhs_ are the values to be compared. |
924 // On exit r0 is 0, positive or negative to indicate the result of | 924 // On exit r0 is 0, positive or negative to indicate the result of |
925 // the comparison. | 925 // the comparison. |
926 void CompareStub::Generate(MacroAssembler* masm) { | 926 void CompareStub::Generate(MacroAssembler* masm) { |
927 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || | 927 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || |
928 (lhs_.is(r1) && rhs_.is(r0))); | 928 (lhs_.is(r1) && rhs_.is(r0))); |
929 | 929 |
930 Label slow; // Call builtin. | 930 Label slow; // Call builtin. |
931 Label not_smis, both_loaded_as_doubles, lhs_not_nan; | 931 Label not_smis, both_loaded_as_doubles, lhs_not_nan; |
932 | 932 |
| 933 if (include_smi_compare_) { |
| 934 Label not_two_smis, smi_done; |
| 935 __ orr(r2, r1, r0); |
| 936 __ tst(r2, Operand(kSmiTagMask)); |
| 937 __ b(ne, ¬_two_smis); |
| 938 __ sub(r0, r1, r0); |
| 939 __ b(vc, &smi_done); |
| 940 // Correct the sign in case of overflow. |
| 941 __ rsb(r0, r0, Operand(0, RelocInfo::NONE)); |
| 942 __ bind(&smi_done); |
| 943 __ Ret(); |
| 944 __ bind(¬_two_smis); |
| 945 } else if (FLAG_debug_code) { |
| 946 __ orr(r2, r1, r0); |
| 947 __ tst(r2, Operand(kSmiTagMask)); |
| 948 __ Assert(nz, "CompareStub: unexpected smi operands."); |
| 949 } |
| 950 |
933 // NOTICE! This code is only reached after a smi-fast-case check, so | 951 // NOTICE! This code is only reached after a smi-fast-case check, so |
934 // it is certain that at least one operand isn't a smi. | 952 // it is certain that at least one operand isn't a smi. |
935 | 953 |
936 // Handle the case where the objects are identical. Either returns the answer | 954 // Handle the case where the objects are identical. Either returns the answer |
937 // or goes to slow. Only falls through if the objects were not identical. | 955 // or goes to slow. Only falls through if the objects were not identical. |
938 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); | 956 EmitIdenticalObjectComparison(masm, &slow, cc_, never_nan_nan_); |
939 | 957 |
940 // If either is a Smi (we know that not both are), then they can only | 958 // If either is a Smi (we know that not both are), then they can only |
941 // be strictly equal if the other is a HeapNumber. | 959 // be strictly equal if the other is a HeapNumber. |
942 STATIC_ASSERT(kSmiTag == 0); | 960 STATIC_ASSERT(kSmiTag == 0); |
(...skipping 1338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2281 } | 2299 } |
2282 | 2300 |
2283 | 2301 |
2284 void StackCheckStub::Generate(MacroAssembler* masm) { | 2302 void StackCheckStub::Generate(MacroAssembler* masm) { |
2285 // Do tail-call to runtime routine. Runtime routines expect at least one | 2303 // Do tail-call to runtime routine. Runtime routines expect at least one |
2286 // argument, so give it a Smi. | 2304 // argument, so give it a Smi. |
2287 __ mov(r0, Operand(Smi::FromInt(0))); | 2305 __ mov(r0, Operand(Smi::FromInt(0))); |
2288 __ push(r0); | 2306 __ push(r0); |
2289 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); | 2307 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); |
2290 | 2308 |
2291 __ StubReturn(1); | 2309 __ Ret(); |
2292 } | 2310 } |
2293 | 2311 |
2294 | 2312 |
2295 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { | 2313 void GenericUnaryOpStub::Generate(MacroAssembler* masm) { |
2296 Label slow, done; | 2314 Label slow, done; |
2297 | 2315 |
2298 Register heap_number_map = r6; | 2316 Register heap_number_map = r6; |
2299 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2317 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
2300 | 2318 |
2301 if (op_ == Token::SUB) { | 2319 if (op_ == Token::SUB) { |
2302 // Check whether the value is a smi. | 2320 if (include_smi_code_) { |
2303 Label try_float; | 2321 // Check whether the value is a smi. |
2304 __ tst(r0, Operand(kSmiTagMask)); | 2322 Label try_float; |
2305 __ b(ne, &try_float); | 2323 __ tst(r0, Operand(kSmiTagMask)); |
| 2324 __ b(ne, &try_float); |
2306 | 2325 |
2307 // Go slow case if the value of the expression is zero | 2326 // Go slow case if the value of the expression is zero |
2308 // to make sure that we switch between 0 and -0. | 2327 // to make sure that we switch between 0 and -0. |
2309 if (negative_zero_ == kStrictNegativeZero) { | 2328 if (negative_zero_ == kStrictNegativeZero) { |
2310 // If we have to check for zero, then we can check for the max negative | 2329 // If we have to check for zero, then we can check for the max negative |
2311 // smi while we are at it. | 2330 // smi while we are at it. |
2312 __ bic(ip, r0, Operand(0x80000000), SetCC); | 2331 __ bic(ip, r0, Operand(0x80000000), SetCC); |
2313 __ b(eq, &slow); | 2332 __ b(eq, &slow); |
2314 __ rsb(r0, r0, Operand(0, RelocInfo::NONE)); | 2333 __ rsb(r0, r0, Operand(0, RelocInfo::NONE)); |
2315 __ StubReturn(1); | 2334 __ Ret(); |
2316 } else { | 2335 } else { |
2317 // The value of the expression is a smi and 0 is OK for -0. Try | 2336 // The value of the expression is a smi and 0 is OK for -0. Try |
2318 // optimistic subtraction '0 - value'. | 2337 // optimistic subtraction '0 - value'. |
2319 __ rsb(r0, r0, Operand(0, RelocInfo::NONE), SetCC); | 2338 __ rsb(r0, r0, Operand(0, RelocInfo::NONE), SetCC); |
2320 __ StubReturn(1, vc); | 2339 __ Ret(vc); |
2321 // We don't have to reverse the optimistic neg since the only case | 2340 // We don't have to reverse the optimistic neg since the only case |
2322 // where we fall through is the minimum negative Smi, which is the case | 2341 // where we fall through is the minimum negative Smi, which is the case |
2323 // where the neg leaves the register unchanged. | 2342 // where the neg leaves the register unchanged. |
2324 __ jmp(&slow); // Go slow on max negative Smi. | 2343 __ jmp(&slow); // Go slow on max negative Smi. |
| 2344 } |
| 2345 __ bind(&try_float); |
| 2346 } else if (FLAG_debug_code) { |
| 2347 __ tst(r0, Operand(kSmiTagMask)); |
| 2348 __ Assert(ne, "Unexpected smi operand."); |
2325 } | 2349 } |
2326 | 2350 |
2327 __ bind(&try_float); | |
2328 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2351 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
2329 __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2352 __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
2330 __ cmp(r1, heap_number_map); | 2353 __ cmp(r1, heap_number_map); |
2331 __ b(ne, &slow); | 2354 __ b(ne, &slow); |
2332 // r0 is a heap number. Get a new heap number in r1. | 2355 // r0 is a heap number. Get a new heap number in r1. |
2333 if (overwrite_ == UNARY_OVERWRITE) { | 2356 if (overwrite_ == UNARY_OVERWRITE) { |
2334 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 2357 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
2335 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. | 2358 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. |
2336 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 2359 __ str(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
2337 } else { | 2360 } else { |
2338 __ AllocateHeapNumber(r1, r2, r3, r6, &slow); | 2361 __ AllocateHeapNumber(r1, r2, r3, r6, &slow); |
2339 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); | 2362 __ ldr(r3, FieldMemOperand(r0, HeapNumber::kMantissaOffset)); |
2340 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); | 2363 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset)); |
2341 __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); | 2364 __ str(r3, FieldMemOperand(r1, HeapNumber::kMantissaOffset)); |
2342 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. | 2365 __ eor(r2, r2, Operand(HeapNumber::kSignMask)); // Flip sign. |
2343 __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); | 2366 __ str(r2, FieldMemOperand(r1, HeapNumber::kExponentOffset)); |
2344 __ mov(r0, Operand(r1)); | 2367 __ mov(r0, Operand(r1)); |
2345 } | 2368 } |
2346 } else if (op_ == Token::BIT_NOT) { | 2369 } else if (op_ == Token::BIT_NOT) { |
| 2370 if (include_smi_code_) { |
| 2371 Label non_smi; |
| 2372 __ BranchOnNotSmi(r0, &non_smi); |
| 2373 __ mvn(r0, Operand(r0)); |
| 2374 // Bit-clear inverted smi-tag. |
| 2375 __ bic(r0, r0, Operand(kSmiTagMask)); |
| 2376 __ Ret(); |
| 2377 __ bind(&non_smi); |
| 2378 } else if (FLAG_debug_code) { |
| 2379 __ tst(r0, Operand(kSmiTagMask)); |
| 2380 __ Assert(ne, "Unexpected smi operand."); |
| 2381 } |
| 2382 |
2347 // Check if the operand is a heap number. | 2383 // Check if the operand is a heap number. |
2348 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 2384 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
2349 __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | 2385 __ AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); |
2350 __ cmp(r1, heap_number_map); | 2386 __ cmp(r1, heap_number_map); |
2351 __ b(ne, &slow); | 2387 __ b(ne, &slow); |
2352 | 2388 |
2353 // Convert the heap number is r0 to an untagged integer in r1. | 2389 // Convert the heap number is r0 to an untagged integer in r1. |
2354 __ ConvertToInt32(r0, r1, r2, r3, &slow); | 2390 __ ConvertToInt32(r0, r1, r2, r3, &slow); |
2355 | 2391 |
2356 // Do the bitwise operation (move negated) and check if the result | 2392 // Do the bitwise operation (move negated) and check if the result |
(...skipping 27 matching lines...) Expand all Loading... |
2384 WriteInt32ToHeapNumberStub stub(r1, r0, r2); | 2420 WriteInt32ToHeapNumberStub stub(r1, r0, r2); |
2385 __ push(lr); | 2421 __ push(lr); |
2386 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); | 2422 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET); |
2387 __ pop(lr); | 2423 __ pop(lr); |
2388 } | 2424 } |
2389 } else { | 2425 } else { |
2390 UNIMPLEMENTED(); | 2426 UNIMPLEMENTED(); |
2391 } | 2427 } |
2392 | 2428 |
2393 __ bind(&done); | 2429 __ bind(&done); |
2394 __ StubReturn(1); | 2430 __ Ret(); |
2395 | 2431 |
2396 // Handle the slow case by jumping to the JavaScript builtin. | 2432 // Handle the slow case by jumping to the JavaScript builtin. |
2397 __ bind(&slow); | 2433 __ bind(&slow); |
2398 __ push(r0); | 2434 __ push(r0); |
2399 switch (op_) { | 2435 switch (op_) { |
2400 case Token::SUB: | 2436 case Token::SUB: |
2401 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); | 2437 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS); |
2402 break; | 2438 break; |
2403 case Token::BIT_NOT: | 2439 case Token::BIT_NOT: |
2404 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_JS); | 2440 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_JS); |
(...skipping 1087 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3492 const char* never_nan_nan_name = ""; | 3528 const char* never_nan_nan_name = ""; |
3493 if (never_nan_nan_ && (cc_ == eq || cc_ == ne)) { | 3529 if (never_nan_nan_ && (cc_ == eq || cc_ == ne)) { |
3494 never_nan_nan_name = "_NO_NAN"; | 3530 never_nan_nan_name = "_NO_NAN"; |
3495 } | 3531 } |
3496 | 3532 |
3497 const char* include_number_compare_name = ""; | 3533 const char* include_number_compare_name = ""; |
3498 if (!include_number_compare_) { | 3534 if (!include_number_compare_) { |
3499 include_number_compare_name = "_NO_NUMBER"; | 3535 include_number_compare_name = "_NO_NUMBER"; |
3500 } | 3536 } |
3501 | 3537 |
| 3538 const char* include_smi_compare_name = ""; |
| 3539 if (!include_smi_compare_) { |
| 3540 include_smi_compare_name = "_NO_SMI"; |
| 3541 } |
| 3542 |
3502 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 3543 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
3503 "CompareStub_%s%s%s%s%s%s", | 3544 "CompareStub_%s%s%s%s%s%s", |
3504 cc_name, | 3545 cc_name, |
3505 lhs_name, | 3546 lhs_name, |
3506 rhs_name, | 3547 rhs_name, |
3507 strict_name, | 3548 strict_name, |
3508 never_nan_nan_name, | 3549 never_nan_nan_name, |
3509 include_number_compare_name); | 3550 include_number_compare_name, |
| 3551 include_smi_compare_name); |
3510 return name_; | 3552 return name_; |
3511 } | 3553 } |
3512 | 3554 |
3513 | 3555 |
3514 int CompareStub::MinorKey() { | 3556 int CompareStub::MinorKey() { |
3515 // Encode the three parameters in a unique 16 bit value. To avoid duplicate | 3557 // Encode the three parameters in a unique 16 bit value. To avoid duplicate |
3516 // stubs the never NaN NaN condition is only taken into account if the | 3558 // stubs the never NaN NaN condition is only taken into account if the |
3517 // condition is equals. | 3559 // condition is equals. |
3518 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 12)); | 3560 ASSERT((static_cast<unsigned>(cc_) >> 28) < (1 << 12)); |
3519 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || | 3561 ASSERT((lhs_.is(r0) && rhs_.is(r1)) || |
3520 (lhs_.is(r1) && rhs_.is(r0))); | 3562 (lhs_.is(r1) && rhs_.is(r0))); |
3521 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) | 3563 return ConditionField::encode(static_cast<unsigned>(cc_) >> 28) |
3522 | RegisterField::encode(lhs_.is(r0)) | 3564 | RegisterField::encode(lhs_.is(r0)) |
3523 | StrictField::encode(strict_) | 3565 | StrictField::encode(strict_) |
3524 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) | 3566 | NeverNanNanField::encode(cc_ == eq ? never_nan_nan_ : false) |
3525 | IncludeNumberCompareField::encode(include_number_compare_); | 3567 | IncludeNumberCompareField::encode(include_number_compare_) |
| 3568 | IncludeSmiCompareField::encode(include_smi_compare_); |
3526 } | 3569 } |
3527 | 3570 |
3528 | 3571 |
3529 // StringCharCodeAtGenerator | 3572 // StringCharCodeAtGenerator |
3530 | 3573 |
3531 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 3574 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
3532 Label flat_string; | 3575 Label flat_string; |
3533 Label ascii_string; | 3576 Label ascii_string; |
3534 Label got_char_code; | 3577 Label got_char_code; |
3535 | 3578 |
(...skipping 601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4137 // both "from" and "to" are smis, and | 4180 // both "from" and "to" are smis, and |
4138 // 0 <= from <= to <= string.length. | 4181 // 0 <= from <= to <= string.length. |
4139 // If any of these assumptions fail, we call the runtime system. | 4182 // If any of these assumptions fail, we call the runtime system. |
4140 | 4183 |
4141 static const int kToOffset = 0 * kPointerSize; | 4184 static const int kToOffset = 0 * kPointerSize; |
4142 static const int kFromOffset = 1 * kPointerSize; | 4185 static const int kFromOffset = 1 * kPointerSize; |
4143 static const int kStringOffset = 2 * kPointerSize; | 4186 static const int kStringOffset = 2 * kPointerSize; |
4144 | 4187 |
4145 | 4188 |
4146 // Check bounds and smi-ness. | 4189 // Check bounds and smi-ness. |
4147 __ ldr(r7, MemOperand(sp, kToOffset)); | 4190 Register to = r6; |
4148 __ ldr(r6, MemOperand(sp, kFromOffset)); | 4191 Register from = r7; |
| 4192 __ Ldrd(to, from, MemOperand(sp, kToOffset)); |
| 4193 STATIC_ASSERT(kFromOffset == kToOffset + 4); |
4149 STATIC_ASSERT(kSmiTag == 0); | 4194 STATIC_ASSERT(kSmiTag == 0); |
4150 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 4195 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
4151 // I.e., arithmetic shift right by one un-smi-tags. | 4196 // I.e., arithmetic shift right by one un-smi-tags. |
4152 __ mov(r2, Operand(r7, ASR, 1), SetCC); | 4197 __ mov(r2, Operand(to, ASR, 1), SetCC); |
4153 __ mov(r3, Operand(r6, ASR, 1), SetCC, cc); | 4198 __ mov(r3, Operand(from, ASR, 1), SetCC, cc); |
4154 // If either r2 or r6 had the smi tag bit set, then carry is set now. | 4199 // If either to or from had the smi tag bit set, then carry is set now. |
4155 __ b(cs, &runtime); // Either "from" or "to" is not a smi. | 4200 __ b(cs, &runtime); // Either "from" or "to" is not a smi. |
4156 __ b(mi, &runtime); // From is negative. | 4201 __ b(mi, &runtime); // From is negative. |
4157 | 4202 |
| 4203 // Both to and from are smis. |
| 4204 |
4158 __ sub(r2, r2, Operand(r3), SetCC); | 4205 __ sub(r2, r2, Operand(r3), SetCC); |
4159 __ b(mi, &runtime); // Fail if from > to. | 4206 __ b(mi, &runtime); // Fail if from > to. |
4160 // Special handling of sub-strings of length 1 and 2. One character strings | 4207 // Special handling of sub-strings of length 1 and 2. One character strings |
4161 // are handled in the runtime system (looked up in the single character | 4208 // are handled in the runtime system (looked up in the single character |
4162 // cache). Two character strings are looked for in the symbol cache. | 4209 // cache). Two character strings are looked for in the symbol cache. |
4163 __ cmp(r2, Operand(2)); | 4210 __ cmp(r2, Operand(2)); |
4164 __ b(lt, &runtime); | 4211 __ b(lt, &runtime); |
4165 | 4212 |
4166 // r2: length | 4213 // r2: length |
4167 // r3: from index (untaged smi) | 4214 // r3: from index (untaged smi) |
4168 // r6: from (smi) | 4215 // r6 (a.k.a. to): to (smi) |
4169 // r7: to (smi) | 4216 // r7 (a.k.a. from): from offset (smi) |
4170 | 4217 |
4171 // Make sure first argument is a sequential (or flat) string. | 4218 // Make sure first argument is a sequential (or flat) string. |
4172 __ ldr(r5, MemOperand(sp, kStringOffset)); | 4219 __ ldr(r5, MemOperand(sp, kStringOffset)); |
4173 STATIC_ASSERT(kSmiTag == 0); | 4220 STATIC_ASSERT(kSmiTag == 0); |
4174 __ tst(r5, Operand(kSmiTagMask)); | 4221 __ tst(r5, Operand(kSmiTagMask)); |
4175 __ b(eq, &runtime); | 4222 __ b(eq, &runtime); |
4176 Condition is_string = masm->IsObjectStringType(r5, r1); | 4223 Condition is_string = masm->IsObjectStringType(r5, r1); |
4177 __ b(NegateCondition(is_string), &runtime); | 4224 __ b(NegateCondition(is_string), &runtime); |
4178 | 4225 |
4179 // r1: instance type | 4226 // r1: instance type |
4180 // r2: length | 4227 // r2: length |
4181 // r3: from index (untaged smi) | 4228 // r3: from index (untagged smi) |
4182 // r5: string | 4229 // r5: string |
4183 // r6: from (smi) | 4230 // r6 (a.k.a. to): to (smi) |
4184 // r7: to (smi) | 4231 // r7 (a.k.a. from): from offset (smi) |
4185 Label seq_string; | 4232 Label seq_string; |
4186 __ and_(r4, r1, Operand(kStringRepresentationMask)); | 4233 __ and_(r4, r1, Operand(kStringRepresentationMask)); |
4187 STATIC_ASSERT(kSeqStringTag < kConsStringTag); | 4234 STATIC_ASSERT(kSeqStringTag < kConsStringTag); |
4188 STATIC_ASSERT(kConsStringTag < kExternalStringTag); | 4235 STATIC_ASSERT(kConsStringTag < kExternalStringTag); |
4189 __ cmp(r4, Operand(kConsStringTag)); | 4236 __ cmp(r4, Operand(kConsStringTag)); |
4190 __ b(gt, &runtime); // External strings go to runtime. | 4237 __ b(gt, &runtime); // External strings go to runtime. |
4191 __ b(lt, &seq_string); // Sequential strings are handled directly. | 4238 __ b(lt, &seq_string); // Sequential strings are handled directly. |
4192 | 4239 |
4193 // Cons string. Try to recurse (once) on the first substring. | 4240 // Cons string. Try to recurse (once) on the first substring. |
4194 // (This adds a little more generality than necessary to handle flattened | 4241 // (This adds a little more generality than necessary to handle flattened |
4195 // cons strings, but not much). | 4242 // cons strings, but not much). |
4196 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); | 4243 __ ldr(r5, FieldMemOperand(r5, ConsString::kFirstOffset)); |
4197 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); | 4244 __ ldr(r4, FieldMemOperand(r5, HeapObject::kMapOffset)); |
4198 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 4245 __ ldrb(r1, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
4199 __ tst(r1, Operand(kStringRepresentationMask)); | 4246 __ tst(r1, Operand(kStringRepresentationMask)); |
4200 STATIC_ASSERT(kSeqStringTag == 0); | 4247 STATIC_ASSERT(kSeqStringTag == 0); |
4201 __ b(ne, &runtime); // Cons and External strings go to runtime. | 4248 __ b(ne, &runtime); // Cons and External strings go to runtime. |
4202 | 4249 |
4203 // Definitly a sequential string. | 4250 // Definitly a sequential string. |
4204 __ bind(&seq_string); | 4251 __ bind(&seq_string); |
4205 | 4252 |
4206 // r1: instance type. | 4253 // r1: instance type. |
4207 // r2: length | 4254 // r2: length |
4208 // r3: from index (untaged smi) | 4255 // r3: from index (untaged smi) |
4209 // r5: string | 4256 // r5: string |
4210 // r6: from (smi) | 4257 // r6 (a.k.a. to): to (smi) |
4211 // r7: to (smi) | 4258 // r7 (a.k.a. from): from offset (smi) |
4212 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); | 4259 __ ldr(r4, FieldMemOperand(r5, String::kLengthOffset)); |
4213 __ cmp(r4, Operand(r7)); | 4260 __ cmp(r4, Operand(to)); |
4214 __ b(lt, &runtime); // Fail if to > length. | 4261 __ b(lt, &runtime); // Fail if to > length. |
| 4262 to = no_reg; |
4215 | 4263 |
4216 // r1: instance type. | 4264 // r1: instance type. |
4217 // r2: result string length. | 4265 // r2: result string length. |
4218 // r3: from index (untaged smi) | 4266 // r3: from index (untaged smi) |
4219 // r5: string. | 4267 // r5: string. |
4220 // r6: from offset (smi) | 4268 // r7 (a.k.a. from): from offset (smi) |
4221 // Check for flat ascii string. | 4269 // Check for flat ascii string. |
4222 Label non_ascii_flat; | 4270 Label non_ascii_flat; |
4223 __ tst(r1, Operand(kStringEncodingMask)); | 4271 __ tst(r1, Operand(kStringEncodingMask)); |
4224 STATIC_ASSERT(kTwoByteStringTag == 0); | 4272 STATIC_ASSERT(kTwoByteStringTag == 0); |
4225 __ b(eq, &non_ascii_flat); | 4273 __ b(eq, &non_ascii_flat); |
4226 | 4274 |
4227 Label result_longer_than_two; | 4275 Label result_longer_than_two; |
4228 __ cmp(r2, Operand(2)); | 4276 __ cmp(r2, Operand(2)); |
4229 __ b(gt, &result_longer_than_two); | 4277 __ b(gt, &result_longer_than_two); |
4230 | 4278 |
(...skipping 21 matching lines...) Expand all Loading... |
4252 __ Ret(); | 4300 __ Ret(); |
4253 | 4301 |
4254 __ bind(&result_longer_than_two); | 4302 __ bind(&result_longer_than_two); |
4255 | 4303 |
4256 // Allocate the result. | 4304 // Allocate the result. |
4257 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); | 4305 __ AllocateAsciiString(r0, r2, r3, r4, r1, &runtime); |
4258 | 4306 |
4259 // r0: result string. | 4307 // r0: result string. |
4260 // r2: result string length. | 4308 // r2: result string length. |
4261 // r5: string. | 4309 // r5: string. |
4262 // r6: from offset (smi) | 4310 // r7 (a.k.a. from): from offset (smi) |
4263 // Locate first character of result. | 4311 // Locate first character of result. |
4264 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 4312 __ add(r1, r0, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
4265 // Locate 'from' character of string. | 4313 // Locate 'from' character of string. |
4266 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 4314 __ add(r5, r5, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
4267 __ add(r5, r5, Operand(r6, ASR, 1)); | 4315 __ add(r5, r5, Operand(from, ASR, 1)); |
4268 | 4316 |
4269 // r0: result string. | 4317 // r0: result string. |
4270 // r1: first character of result string. | 4318 // r1: first character of result string. |
4271 // r2: result string length. | 4319 // r2: result string length. |
4272 // r5: first character of sub string to copy. | 4320 // r5: first character of sub string to copy. |
4273 STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); | 4321 STATIC_ASSERT((SeqAsciiString::kHeaderSize & kObjectAlignmentMask) == 0); |
4274 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 4322 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, |
4275 COPY_ASCII | DEST_ALWAYS_ALIGNED); | 4323 COPY_ASCII | DEST_ALWAYS_ALIGNED); |
4276 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 4324 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
4277 __ add(sp, sp, Operand(3 * kPointerSize)); | 4325 __ add(sp, sp, Operand(3 * kPointerSize)); |
4278 __ Ret(); | 4326 __ Ret(); |
4279 | 4327 |
4280 __ bind(&non_ascii_flat); | 4328 __ bind(&non_ascii_flat); |
4281 // r2: result string length. | 4329 // r2: result string length. |
4282 // r5: string. | 4330 // r5: string. |
4283 // r6: from offset (smi) | 4331 // r7 (a.k.a. from): from offset (smi) |
4284 // Check for flat two byte string. | 4332 // Check for flat two byte string. |
4285 | 4333 |
4286 // Allocate the result. | 4334 // Allocate the result. |
4287 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); | 4335 __ AllocateTwoByteString(r0, r2, r1, r3, r4, &runtime); |
4288 | 4336 |
4289 // r0: result string. | 4337 // r0: result string. |
4290 // r2: result string length. | 4338 // r2: result string length. |
4291 // r5: string. | 4339 // r5: string. |
4292 // Locate first character of result. | 4340 // Locate first character of result. |
4293 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 4341 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
4294 // Locate 'from' character of string. | 4342 // Locate 'from' character of string. |
4295 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 4343 __ add(r5, r5, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
4296 // As "from" is a smi it is 2 times the value which matches the size of a two | 4344 // As "from" is a smi it is 2 times the value which matches the size of a two |
4297 // byte character. | 4345 // byte character. |
4298 __ add(r5, r5, Operand(r6)); | 4346 __ add(r5, r5, Operand(from)); |
| 4347 from = no_reg; |
4299 | 4348 |
4300 // r0: result string. | 4349 // r0: result string. |
4301 // r1: first character of result. | 4350 // r1: first character of result. |
4302 // r2: result length. | 4351 // r2: result length. |
4303 // r5: first character of string to copy. | 4352 // r5: first character of string to copy. |
4304 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 4353 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
4305 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r7, r9, | 4354 StringHelper::GenerateCopyCharactersLong( |
4306 DEST_ALWAYS_ALIGNED); | 4355 masm, r1, r5, r2, r3, r4, r6, r7, r9, DEST_ALWAYS_ALIGNED); |
4307 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); | 4356 __ IncrementCounter(&Counters::sub_string_native, 1, r3, r4); |
4308 __ add(sp, sp, Operand(3 * kPointerSize)); | 4357 __ add(sp, sp, Operand(3 * kPointerSize)); |
4309 __ Ret(); | 4358 __ Ret(); |
4310 | 4359 |
4311 // Just jump to runtime to create the sub string. | 4360 // Just jump to runtime to create the sub string. |
4312 __ bind(&runtime); | 4361 __ bind(&runtime); |
4313 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 4362 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
4314 } | 4363 } |
4315 | 4364 |
4316 | 4365 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4372 __ Ret(); | 4421 __ Ret(); |
4373 } | 4422 } |
4374 | 4423 |
4375 | 4424 |
4376 void StringCompareStub::Generate(MacroAssembler* masm) { | 4425 void StringCompareStub::Generate(MacroAssembler* masm) { |
4377 Label runtime; | 4426 Label runtime; |
4378 | 4427 |
4379 // Stack frame on entry. | 4428 // Stack frame on entry. |
4380 // sp[0]: right string | 4429 // sp[0]: right string |
4381 // sp[4]: left string | 4430 // sp[4]: left string |
4382 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // left | 4431 __ Ldrd(r0 , r1, MemOperand(sp)); // Load right in r0, left in r1. |
4383 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // right | |
4384 | 4432 |
4385 Label not_same; | 4433 Label not_same; |
4386 __ cmp(r0, r1); | 4434 __ cmp(r0, r1); |
4387 __ b(ne, ¬_same); | 4435 __ b(ne, ¬_same); |
4388 STATIC_ASSERT(EQUAL == 0); | 4436 STATIC_ASSERT(EQUAL == 0); |
4389 STATIC_ASSERT(kSmiTag == 0); | 4437 STATIC_ASSERT(kSmiTag == 0); |
4390 __ mov(r0, Operand(Smi::FromInt(EQUAL))); | 4438 __ mov(r0, Operand(Smi::FromInt(EQUAL))); |
4391 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2); | 4439 __ IncrementCounter(&Counters::string_compare_native, 1, r1, r2); |
4392 __ add(sp, sp, Operand(2 * kPointerSize)); | 4440 __ add(sp, sp, Operand(2 * kPointerSize)); |
4393 __ Ret(); | 4441 __ Ret(); |
4394 | 4442 |
4395 __ bind(¬_same); | 4443 __ bind(¬_same); |
4396 | 4444 |
4397 // Check that both objects are sequential ascii strings. | 4445 // Check that both objects are sequential ascii strings. |
4398 __ JumpIfNotBothSequentialAsciiStrings(r0, r1, r2, r3, &runtime); | 4446 __ JumpIfNotBothSequentialAsciiStrings(r1, r0, r2, r3, &runtime); |
4399 | 4447 |
4400 // Compare flat ascii strings natively. Remove arguments from stack first. | 4448 // Compare flat ascii strings natively. Remove arguments from stack first. |
4401 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); | 4449 __ IncrementCounter(&Counters::string_compare_native, 1, r2, r3); |
4402 __ add(sp, sp, Operand(2 * kPointerSize)); | 4450 __ add(sp, sp, Operand(2 * kPointerSize)); |
4403 GenerateCompareFlatAsciiStrings(masm, r0, r1, r2, r3, r4, r5); | 4451 GenerateCompareFlatAsciiStrings(masm, r1, r0, r2, r3, r4, r5); |
4404 | 4452 |
4405 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 4453 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
4406 // tagged as a small integer. | 4454 // tagged as a small integer. |
4407 __ bind(&runtime); | 4455 __ bind(&runtime); |
4408 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4456 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
4409 } | 4457 } |
4410 | 4458 |
4411 | 4459 |
4412 void StringAddStub::Generate(MacroAssembler* masm) { | 4460 void StringAddStub::Generate(MacroAssembler* masm) { |
4413 Label string_add_runtime; | 4461 Label string_add_runtime; |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4679 __ bind(&string_add_runtime); | 4727 __ bind(&string_add_runtime); |
4680 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 4728 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
4681 } | 4729 } |
4682 | 4730 |
4683 | 4731 |
4684 #undef __ | 4732 #undef __ |
4685 | 4733 |
4686 } } // namespace v8::internal | 4734 } } // namespace v8::internal |
4687 | 4735 |
4688 #endif // V8_TARGET_ARCH_ARM | 4736 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |