| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| (...skipping 3304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3315 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3315 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
| 3316 } | 3316 } |
| 3317 | 3317 |
| 3318 | 3318 |
| 3319 enum CopyCharactersFlags { | 3319 enum CopyCharactersFlags { |
| 3320 COPY_ASCII = 1, | 3320 COPY_ASCII = 1, |
| 3321 DEST_ALWAYS_ALIGNED = 2 | 3321 DEST_ALWAYS_ALIGNED = 2 |
| 3322 }; | 3322 }; |
| 3323 | 3323 |
| 3324 | 3324 |
| 3325 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, | 3325 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, |
| 3326 Register dest, | 3326 Register dest, |
| 3327 Register src, | 3327 Register src, |
| 3328 Register count, | 3328 Register count, |
| 3329 Register scratch1, | 3329 Register scratch, |
| 3330 Register scratch2, | 3330 String::Encoding encoding) { |
| 3331 Register scratch3, | 3331 if (FLAG_debug_code) { |
| 3332 Register scratch4, | 3332 // Check that destination is word aligned. |
| 3333 int flags) { | |
| 3334 bool ascii = (flags & COPY_ASCII) != 0; | |
| 3335 bool dest_always_aligned = (flags & DEST_ALWAYS_ALIGNED) != 0; | |
| 3336 | |
| 3337 if (dest_always_aligned && FLAG_debug_code) { | |
| 3338 // Check that destination is actually word aligned if the flag says | |
| 3339 // that it is. | |
| 3340 __ tst(dest, Operand(kPointerAlignmentMask)); | 3333 __ tst(dest, Operand(kPointerAlignmentMask)); |
| 3341 __ Check(eq, kDestinationOfCopyNotAligned); | 3334 __ Check(eq, kDestinationOfCopyNotAligned); |
| 3342 } | 3335 } |
| 3343 | 3336 |
| 3344 const int kReadAlignment = 4; | |
| 3345 const int kReadAlignmentMask = kReadAlignment - 1; | |
| 3346 // Ensure that reading an entire aligned word containing the last character | |
| 3347 // of a string will not read outside the allocated area (because we pad up | |
| 3348 // to kObjectAlignment). | |
| 3349 STATIC_ASSERT(kObjectAlignment >= kReadAlignment); | |
| 3350 // Assumes word reads and writes are little endian. | 3337 // Assumes word reads and writes are little endian. |
| 3351 // Nothing to do for zero characters. | 3338 // Nothing to do for zero characters. |
| 3352 Label done; | 3339 Label done; |
| 3353 if (!ascii) { | 3340 if (encoding == String::TWO_BYTE_ENCODING) { |
| 3354 __ add(count, count, Operand(count), SetCC); | 3341 __ add(count, count, Operand(count), SetCC); |
| 3355 } else { | |
| 3356 __ cmp(count, Operand::Zero()); | |
| 3357 } | |
| 3358 __ b(eq, &done); | |
| 3359 | |
| 3360 // Assume that you cannot read (or write) unaligned. | |
| 3361 Label byte_loop; | |
| 3362 // Must copy at least eight bytes, otherwise just do it one byte at a time. | |
| 3363 __ cmp(count, Operand(8)); | |
| 3364 __ add(count, dest, Operand(count)); | |
| 3365 Register limit = count; // Read until src equals this. | |
| 3366 __ b(lt, &byte_loop); | |
| 3367 | |
| 3368 if (!dest_always_aligned) { | |
| 3369 // Align dest by byte copying. Copies between zero and three bytes. | |
| 3370 __ and_(scratch4, dest, Operand(kReadAlignmentMask), SetCC); | |
| 3371 Label dest_aligned; | |
| 3372 __ b(eq, &dest_aligned); | |
| 3373 __ cmp(scratch4, Operand(2)); | |
| 3374 __ ldrb(scratch1, MemOperand(src, 1, PostIndex)); | |
| 3375 __ ldrb(scratch2, MemOperand(src, 1, PostIndex), le); | |
| 3376 __ ldrb(scratch3, MemOperand(src, 1, PostIndex), lt); | |
| 3377 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | |
| 3378 __ strb(scratch2, MemOperand(dest, 1, PostIndex), le); | |
| 3379 __ strb(scratch3, MemOperand(dest, 1, PostIndex), lt); | |
| 3380 __ bind(&dest_aligned); | |
| 3381 } | 3342 } |
| 3382 | 3343 |
| 3383 Label simple_loop; | 3344 Register limit = count; // Read until dest equals this. |
| 3345 __ add(limit, dest, Operand(count)); |
| 3384 | 3346 |
| 3385 __ sub(scratch4, dest, Operand(src)); | 3347 Label loop_entry, loop; |
| 3386 __ and_(scratch4, scratch4, Operand(0x03), SetCC); | 3348 // Copy bytes from src to dest until dest hits limit. |
| 3387 __ b(eq, &simple_loop); | 3349 __ b(&loop_entry); |
| 3388 // Shift register is number of bits in a source word that | 3350 __ bind(&loop); |
| 3389 // must be combined with bits in the next source word in order | 3351 __ ldrb(scratch, MemOperand(src, 1, PostIndex), lt); |
| 3390 // to create a destination word. | 3352 __ strb(scratch, MemOperand(dest, 1, PostIndex)); |
| 3391 | 3353 __ bind(&loop_entry); |
| 3392 // Complex loop for src/dst that are not aligned the same way. | |
| 3393 { | |
| 3394 Label loop; | |
| 3395 __ mov(scratch4, Operand(scratch4, LSL, 3)); | |
| 3396 Register left_shift = scratch4; | |
| 3397 __ and_(src, src, Operand(~3)); // Round down to load previous word. | |
| 3398 __ ldr(scratch1, MemOperand(src, 4, PostIndex)); | |
| 3399 // Store the "shift" most significant bits of scratch in the least | |
| 3400 // signficant bits (i.e., shift down by (32-shift)). | |
| 3401 __ rsb(scratch2, left_shift, Operand(32)); | |
| 3402 Register right_shift = scratch2; | |
| 3403 __ mov(scratch1, Operand(scratch1, LSR, right_shift)); | |
| 3404 | |
| 3405 __ bind(&loop); | |
| 3406 __ ldr(scratch3, MemOperand(src, 4, PostIndex)); | |
| 3407 __ orr(scratch1, scratch1, Operand(scratch3, LSL, left_shift)); | |
| 3408 __ str(scratch1, MemOperand(dest, 4, PostIndex)); | |
| 3409 __ mov(scratch1, Operand(scratch3, LSR, right_shift)); | |
| 3410 // Loop if four or more bytes left to copy. | |
| 3411 __ sub(scratch3, limit, Operand(dest)); | |
| 3412 __ sub(scratch3, scratch3, Operand(4), SetCC); | |
| 3413 __ b(ge, &loop); | |
| 3414 } | |
| 3415 // There is now between zero and three bytes left to copy (negative that | |
| 3416 // number is in scratch3), and between one and three bytes already read into | |
| 3417 // scratch1 (eight times that number in scratch4). We may have read past | |
| 3418 // the end of the string, but because objects are aligned, we have not read | |
| 3419 // past the end of the object. | |
| 3420 // Find the minimum of remaining characters to move and preloaded characters | |
| 3421 // and write those as bytes. | |
| 3422 __ add(scratch3, scratch3, Operand(4), SetCC); | |
| 3423 __ b(eq, &done); | |
| 3424 __ cmp(scratch4, Operand(scratch3, LSL, 3), ne); | |
| 3425 // Move minimum of bytes read and bytes left to copy to scratch4. | |
| 3426 __ mov(scratch3, Operand(scratch4, LSR, 3), LeaveCC, lt); | |
| 3427 // Between one and three (value in scratch3) characters already read into | |
| 3428 // scratch ready to write. | |
| 3429 __ cmp(scratch3, Operand(2)); | |
| 3430 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | |
| 3431 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, ge); | |
| 3432 __ strb(scratch1, MemOperand(dest, 1, PostIndex), ge); | |
| 3433 __ mov(scratch1, Operand(scratch1, LSR, 8), LeaveCC, gt); | |
| 3434 __ strb(scratch1, MemOperand(dest, 1, PostIndex), gt); | |
| 3435 // Copy any remaining bytes. | |
| 3436 __ b(&byte_loop); | |
| 3437 | |
| 3438 // Simple loop. | |
| 3439 // Copy words from src to dst, until less than four bytes left. | |
| 3440 // Both src and dest are word aligned. | |
| 3441 __ bind(&simple_loop); | |
| 3442 { | |
| 3443 Label loop; | |
| 3444 __ bind(&loop); | |
| 3445 __ ldr(scratch1, MemOperand(src, 4, PostIndex)); | |
| 3446 __ sub(scratch3, limit, Operand(dest)); | |
| 3447 __ str(scratch1, MemOperand(dest, 4, PostIndex)); | |
| 3448 // Compare to 8, not 4, because we do the substraction before increasing | |
| 3449 // dest. | |
| 3450 __ cmp(scratch3, Operand(8)); | |
| 3451 __ b(ge, &loop); | |
| 3452 } | |
| 3453 | |
| 3454 // Copy bytes from src to dst until dst hits limit. | |
| 3455 __ bind(&byte_loop); | |
| 3456 __ cmp(dest, Operand(limit)); | 3354 __ cmp(dest, Operand(limit)); |
| 3457 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); | 3355 __ b(lt, &loop); |
| 3458 __ b(ge, &done); | |
| 3459 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | |
| 3460 __ b(&byte_loop); | |
| 3461 | 3356 |
| 3462 __ bind(&done); | 3357 __ bind(&done); |
| 3463 } | 3358 } |
| 3464 | 3359 |
| 3465 | 3360 |
| 3466 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3361 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 3467 Register hash, | 3362 Register hash, |
| 3468 Register character) { | 3363 Register character) { |
| 3469 // hash = character + (character << 10); | 3364 // hash = character + (character << 10); |
| 3470 __ LoadRoot(hash, Heap::kHashSeedRootIndex); | 3365 __ LoadRoot(hash, Heap::kHashSeedRootIndex); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3676 // Locate first character of substring to copy. | 3571 // Locate first character of substring to copy. |
| 3677 __ add(r5, r5, r3); | 3572 __ add(r5, r5, r3); |
| 3678 // Locate first character of result. | 3573 // Locate first character of result. |
| 3679 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3574 __ add(r1, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| 3680 | 3575 |
| 3681 // r0: result string | 3576 // r0: result string |
| 3682 // r1: first character of result string | 3577 // r1: first character of result string |
| 3683 // r2: result string length | 3578 // r2: result string length |
| 3684 // r5: first character of substring to copy | 3579 // r5: first character of substring to copy |
| 3685 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 3580 STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 3686 StringHelper::GenerateCopyCharactersLong(masm, r1, r5, r2, r3, r4, r6, r9, | 3581 StringHelper::GenerateCopyCharacters( |
| 3687 COPY_ASCII | DEST_ALWAYS_ALIGNED); | 3582 masm, r1, r5, r2, r3, String::ONE_BYTE_ENCODING); |
| 3688 __ jmp(&return_r0); | 3583 __ jmp(&return_r0); |
| 3689 | 3584 |
| 3690 // Allocate and copy the resulting two-byte string. | 3585 // Allocate and copy the resulting two-byte string. |
| 3691 __ bind(&two_byte_sequential); | 3586 __ bind(&two_byte_sequential); |
| 3692 __ AllocateTwoByteString(r0, r2, r4, r6, r1, &runtime); | 3587 __ AllocateTwoByteString(r0, r2, r4, r6, r1, &runtime); |
| 3693 | 3588 |
| 3694 // Locate first character of substring to copy. | 3589 // Locate first character of substring to copy. |
| 3695 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 3590 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| 3696 __ add(r5, r5, Operand(r3, LSL, 1)); | 3591 __ add(r5, r5, Operand(r3, LSL, 1)); |
| 3697 // Locate first character of result. | 3592 // Locate first character of result. |
| 3698 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 3593 __ add(r1, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 3699 | 3594 |
| 3700 // r0: result string. | 3595 // r0: result string. |
| 3701 // r1: first character of result. | 3596 // r1: first character of result. |
| 3702 // r2: result length. | 3597 // r2: result length. |
| 3703 // r5: first character of substring to copy. | 3598 // r5: first character of substring to copy. |
| 3704 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); | 3599 STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0); |
| 3705 StringHelper::GenerateCopyCharactersLong( | 3600 StringHelper::GenerateCopyCharacters( |
| 3706 masm, r1, r5, r2, r3, r4, r6, r9, DEST_ALWAYS_ALIGNED); | 3601 masm, r1, r5, r2, r3, String::TWO_BYTE_ENCODING); |
| 3707 | 3602 |
| 3708 __ bind(&return_r0); | 3603 __ bind(&return_r0); |
| 3709 Counters* counters = isolate()->counters(); | 3604 Counters* counters = isolate()->counters(); |
| 3710 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); | 3605 __ IncrementCounter(counters->sub_string_native(), 1, r3, r4); |
| 3711 __ Drop(3); | 3606 __ Drop(3); |
| 3712 __ Ret(); | 3607 __ Ret(); |
| 3713 | 3608 |
| 3714 // Just jump to runtime to create the sub string. | 3609 // Just jump to runtime to create the sub string. |
| 3715 __ bind(&runtime); | 3610 __ bind(&runtime); |
| 3716 __ TailCallRuntime(Runtime::kHiddenSubString, 3, 1); | 3611 __ TailCallRuntime(Runtime::kHiddenSubString, 3, 1); |
| (...skipping 1557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5274 MemOperand(fp, 6 * kPointerSize), | 5169 MemOperand(fp, 6 * kPointerSize), |
| 5275 NULL); | 5170 NULL); |
| 5276 } | 5171 } |
| 5277 | 5172 |
| 5278 | 5173 |
| 5279 #undef __ | 5174 #undef __ |
| 5280 | 5175 |
| 5281 } } // namespace v8::internal | 5176 } } // namespace v8::internal |
| 5282 | 5177 |
| 5283 #endif // V8_TARGET_ARCH_ARM | 5178 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |