| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 Isolate* isolate, | 343 Isolate* isolate, |
| 344 CodeStubInterfaceDescriptor* descriptor) { | 344 CodeStubInterfaceDescriptor* descriptor) { |
| 345 static Register registers[] = { r2, r1, r0 }; | 345 static Register registers[] = { r2, r1, r0 }; |
| 346 descriptor->register_param_count_ = 3; | 346 descriptor->register_param_count_ = 3; |
| 347 descriptor->register_params_ = registers; | 347 descriptor->register_params_ = registers; |
| 348 descriptor->deoptimization_handler_ = | 348 descriptor->deoptimization_handler_ = |
| 349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); | 349 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
| 350 } | 350 } |
| 351 | 351 |
| 352 | 352 |
| 353 void NewStringAddStub::InitializeInterfaceDescriptor( | 353 void StringAddStub::InitializeInterfaceDescriptor( |
| 354 Isolate* isolate, | 354 Isolate* isolate, |
| 355 CodeStubInterfaceDescriptor* descriptor) { | 355 CodeStubInterfaceDescriptor* descriptor) { |
| 356 static Register registers[] = { r1, r0 }; | 356 static Register registers[] = { r1, r0 }; |
| 357 descriptor->register_param_count_ = 2; | 357 descriptor->register_param_count_ = 2; |
| 358 descriptor->register_params_ = registers; | 358 descriptor->register_params_ = registers; |
| 359 descriptor->deoptimization_handler_ = | 359 descriptor->deoptimization_handler_ = |
| 360 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 360 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
| 361 } | 361 } |
| 362 | 362 |
| 363 | 363 |
| (...skipping 3097 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3461 __ push(code_); | 3461 __ push(code_); |
| 3462 __ CallRuntime(Runtime::kCharFromCode, 1); | 3462 __ CallRuntime(Runtime::kCharFromCode, 1); |
| 3463 __ Move(result_, r0); | 3463 __ Move(result_, r0); |
| 3464 call_helper.AfterCall(masm); | 3464 call_helper.AfterCall(masm); |
| 3465 __ jmp(&exit_); | 3465 __ jmp(&exit_); |
| 3466 | 3466 |
| 3467 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3467 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
| 3468 } | 3468 } |
| 3469 | 3469 |
| 3470 | 3470 |
| 3471 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | |
| 3472 Register dest, | |
| 3473 Register src, | |
| 3474 Register count, | |
| 3475 Register scratch, | |
| 3476 bool ascii) { | |
| 3477 Label loop; | |
| 3478 Label done; | |
| 3479 // This loop just copies one character at a time, as it is only used for very | |
| 3480 // short strings. | |
| 3481 if (!ascii) { | |
| 3482 __ add(count, count, Operand(count), SetCC); | |
| 3483 } else { | |
| 3484 __ cmp(count, Operand::Zero()); | |
| 3485 } | |
| 3486 __ b(eq, &done); | |
| 3487 | |
| 3488 __ bind(&loop); | |
| 3489 __ ldrb(scratch, MemOperand(src, 1, PostIndex)); | |
| 3490 // Perform sub between load and dependent store to get the load time to | |
| 3491 // complete. | |
| 3492 __ sub(count, count, Operand(1), SetCC); | |
| 3493 __ strb(scratch, MemOperand(dest, 1, PostIndex)); | |
| 3494 // last iteration. | |
| 3495 __ b(gt, &loop); | |
| 3496 | |
| 3497 __ bind(&done); | |
| 3498 } | |
| 3499 | |
| 3500 | |
| 3501 enum CopyCharactersFlags { | 3471 enum CopyCharactersFlags { |
| 3502 COPY_ASCII = 1, | 3472 COPY_ASCII = 1, |
| 3503 DEST_ALWAYS_ALIGNED = 2 | 3473 DEST_ALWAYS_ALIGNED = 2 |
| 3504 }; | 3474 }; |
| 3505 | 3475 |
| 3506 | 3476 |
| 3507 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, | 3477 void StringHelper::GenerateCopyCharactersLong(MacroAssembler* masm, |
| 3508 Register dest, | 3478 Register dest, |
| 3509 Register src, | 3479 Register src, |
| 3510 Register count, | 3480 Register count, |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3638 __ cmp(dest, Operand(limit)); | 3608 __ cmp(dest, Operand(limit)); |
| 3639 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); | 3609 __ ldrb(scratch1, MemOperand(src, 1, PostIndex), lt); |
| 3640 __ b(ge, &done); | 3610 __ b(ge, &done); |
| 3641 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); | 3611 __ strb(scratch1, MemOperand(dest, 1, PostIndex)); |
| 3642 __ b(&byte_loop); | 3612 __ b(&byte_loop); |
| 3643 | 3613 |
| 3644 __ bind(&done); | 3614 __ bind(&done); |
| 3645 } | 3615 } |
| 3646 | 3616 |
| 3647 | 3617 |
| 3648 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | |
| 3649 Register c1, | |
| 3650 Register c2, | |
| 3651 Register scratch1, | |
| 3652 Register scratch2, | |
| 3653 Register scratch3, | |
| 3654 Register scratch4, | |
| 3655 Register scratch5, | |
| 3656 Label* not_found) { | |
| 3657 // Register scratch3 is the general scratch register in this function. | |
| 3658 Register scratch = scratch3; | |
| 3659 | |
| 3660 // Make sure that both characters are not digits as such strings has a | |
| 3661 // different hash algorithm. Don't try to look for these in the string table. | |
| 3662 Label not_array_index; | |
| 3663 __ sub(scratch, c1, Operand(static_cast<int>('0'))); | |
| 3664 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); | |
| 3665 __ b(hi, ¬_array_index); | |
| 3666 __ sub(scratch, c2, Operand(static_cast<int>('0'))); | |
| 3667 __ cmp(scratch, Operand(static_cast<int>('9' - '0'))); | |
| 3668 | |
| 3669 // If check failed combine both characters into single halfword. | |
| 3670 // This is required by the contract of the method: code at the | |
| 3671 // not_found branch expects this combination in c1 register | |
| 3672 __ orr(c1, c1, Operand(c2, LSL, kBitsPerByte), LeaveCC, ls); | |
| 3673 __ b(ls, not_found); | |
| 3674 | |
| 3675 __ bind(¬_array_index); | |
| 3676 // Calculate the two character string hash. | |
| 3677 Register hash = scratch1; | |
| 3678 StringHelper::GenerateHashInit(masm, hash, c1); | |
| 3679 StringHelper::GenerateHashAddCharacter(masm, hash, c2); | |
| 3680 StringHelper::GenerateHashGetHash(masm, hash); | |
| 3681 | |
| 3682 // Collect the two characters in a register. | |
| 3683 Register chars = c1; | |
| 3684 __ orr(chars, chars, Operand(c2, LSL, kBitsPerByte)); | |
| 3685 | |
| 3686 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3687 // hash: hash of two character string. | |
| 3688 | |
| 3689 // Load string table | |
| 3690 // Load address of first element of the string table. | |
| 3691 Register string_table = c2; | |
| 3692 __ LoadRoot(string_table, Heap::kStringTableRootIndex); | |
| 3693 | |
| 3694 Register undefined = scratch4; | |
| 3695 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); | |
| 3696 | |
| 3697 // Calculate capacity mask from the string table capacity. | |
| 3698 Register mask = scratch2; | |
| 3699 __ ldr(mask, FieldMemOperand(string_table, StringTable::kCapacityOffset)); | |
| 3700 __ mov(mask, Operand(mask, ASR, 1)); | |
| 3701 __ sub(mask, mask, Operand(1)); | |
| 3702 | |
| 3703 // Calculate untagged address of the first element of the string table. | |
| 3704 Register first_string_table_element = string_table; | |
| 3705 __ add(first_string_table_element, string_table, | |
| 3706 Operand(StringTable::kElementsStartOffset - kHeapObjectTag)); | |
| 3707 | |
| 3708 // Registers | |
| 3709 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3710 // hash: hash of two character string | |
| 3711 // mask: capacity mask | |
| 3712 // first_string_table_element: address of the first element of | |
| 3713 // the string table | |
| 3714 // undefined: the undefined object | |
| 3715 // scratch: - | |
| 3716 | |
| 3717 // Perform a number of probes in the string table. | |
| 3718 const int kProbes = 4; | |
| 3719 Label found_in_string_table; | |
| 3720 Label next_probe[kProbes]; | |
| 3721 Register candidate = scratch5; // Scratch register contains candidate. | |
| 3722 for (int i = 0; i < kProbes; i++) { | |
| 3723 // Calculate entry in string table. | |
| 3724 if (i > 0) { | |
| 3725 __ add(candidate, hash, Operand(StringTable::GetProbeOffset(i))); | |
| 3726 } else { | |
| 3727 __ mov(candidate, hash); | |
| 3728 } | |
| 3729 | |
| 3730 __ and_(candidate, candidate, Operand(mask)); | |
| 3731 | |
| 3732 // Load the entry from the symble table. | |
| 3733 STATIC_ASSERT(StringTable::kEntrySize == 1); | |
| 3734 __ ldr(candidate, | |
| 3735 MemOperand(first_string_table_element, | |
| 3736 candidate, | |
| 3737 LSL, | |
| 3738 kPointerSizeLog2)); | |
| 3739 | |
| 3740 // If entry is undefined no string with this hash can be found. | |
| 3741 Label is_string; | |
| 3742 __ CompareObjectType(candidate, scratch, scratch, ODDBALL_TYPE); | |
| 3743 __ b(ne, &is_string); | |
| 3744 | |
| 3745 __ cmp(undefined, candidate); | |
| 3746 __ b(eq, not_found); | |
| 3747 // Must be the hole (deleted entry). | |
| 3748 if (FLAG_debug_code) { | |
| 3749 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
| 3750 __ cmp(ip, candidate); | |
| 3751 __ Assert(eq, kOddballInStringTableIsNotUndefinedOrTheHole); | |
| 3752 } | |
| 3753 __ jmp(&next_probe[i]); | |
| 3754 | |
| 3755 __ bind(&is_string); | |
| 3756 | |
| 3757 // Check that the candidate is a non-external ASCII string. The instance | |
| 3758 // type is still in the scratch register from the CompareObjectType | |
| 3759 // operation. | |
| 3760 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &next_probe[i]); | |
| 3761 | |
| 3762 // If length is not 2 the string is not a candidate. | |
| 3763 __ ldr(scratch, FieldMemOperand(candidate, String::kLengthOffset)); | |
| 3764 __ cmp(scratch, Operand(Smi::FromInt(2))); | |
| 3765 __ b(ne, &next_probe[i]); | |
| 3766 | |
| 3767 // Check if the two characters match. | |
| 3768 // Assumes that word load is little endian. | |
| 3769 __ ldrh(scratch, FieldMemOperand(candidate, SeqOneByteString::kHeaderSize)); | |
| 3770 __ cmp(chars, scratch); | |
| 3771 __ b(eq, &found_in_string_table); | |
| 3772 __ bind(&next_probe[i]); | |
| 3773 } | |
| 3774 | |
| 3775 // No matching 2 character string found by probing. | |
| 3776 __ jmp(not_found); | |
| 3777 | |
| 3778 // Scratch register contains result when we fall through to here. | |
| 3779 Register result = candidate; | |
| 3780 __ bind(&found_in_string_table); | |
| 3781 __ Move(r0, result); | |
| 3782 } | |
| 3783 | |
| 3784 | |
| 3785 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3618 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 3786 Register hash, | 3619 Register hash, |
| 3787 Register character) { | 3620 Register character) { |
| 3788 // hash = character + (character << 10); | 3621 // hash = character + (character << 10); |
| 3789 __ LoadRoot(hash, Heap::kHashSeedRootIndex); | 3622 __ LoadRoot(hash, Heap::kHashSeedRootIndex); |
| 3790 // Untag smi seed and add the character. | 3623 // Untag smi seed and add the character. |
| 3791 __ add(hash, character, Operand(hash, LSR, kSmiTagSize)); | 3624 __ add(hash, character, Operand(hash, LSR, kSmiTagSize)); |
| 3792 // hash += hash << 10; | 3625 // hash += hash << 10; |
| 3793 __ add(hash, hash, Operand(hash, LSL, 10)); | 3626 __ add(hash, hash, Operand(hash, LSL, 10)); |
| 3794 // hash ^= hash >> 6; | 3627 // hash ^= hash >> 6; |
| (...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4426 __ Assert(eq, kExpectedAllocationSite); | 4259 __ Assert(eq, kExpectedAllocationSite); |
| 4427 } | 4260 } |
| 4428 | 4261 |
| 4429 // Tail call into the stub that handles binary operations with allocation | 4262 // Tail call into the stub that handles binary operations with allocation |
| 4430 // sites. | 4263 // sites. |
| 4431 BinaryOpWithAllocationSiteStub stub(state_); | 4264 BinaryOpWithAllocationSiteStub stub(state_); |
| 4432 __ TailCallStub(&stub); | 4265 __ TailCallStub(&stub); |
| 4433 } | 4266 } |
| 4434 | 4267 |
| 4435 | 4268 |
| 4436 void StringAddStub::Generate(MacroAssembler* masm) { | |
| 4437 Label call_runtime, call_builtin; | |
| 4438 Builtins::JavaScript builtin_id = Builtins::ADD; | |
| 4439 | |
| 4440 Counters* counters = masm->isolate()->counters(); | |
| 4441 | |
| 4442 // Stack on entry: | |
| 4443 // sp[0]: second argument (right). | |
| 4444 // sp[4]: first argument (left). | |
| 4445 | |
| 4446 // Load the two arguments. | |
| 4447 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. | |
| 4448 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | |
| 4449 | |
| 4450 // Make sure that both arguments are strings if not known in advance. | |
| 4451 // Otherwise, at least one of the arguments is definitely a string, | |
| 4452 // and we convert the one that is not known to be a string. | |
| 4453 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { | |
| 4454 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); | |
| 4455 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); | |
| 4456 __ JumpIfEitherSmi(r0, r1, &call_runtime); | |
| 4457 // Load instance types. | |
| 4458 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
| 4459 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
| 4460 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | |
| 4461 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | |
| 4462 STATIC_ASSERT(kStringTag == 0); | |
| 4463 // If either is not a string, go to runtime. | |
| 4464 __ tst(r4, Operand(kIsNotStringMask)); | |
| 4465 __ tst(r5, Operand(kIsNotStringMask), eq); | |
| 4466 __ b(ne, &call_runtime); | |
| 4467 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { | |
| 4468 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); | |
| 4469 GenerateConvertArgument( | |
| 4470 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin); | |
| 4471 builtin_id = Builtins::STRING_ADD_RIGHT; | |
| 4472 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { | |
| 4473 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); | |
| 4474 GenerateConvertArgument( | |
| 4475 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin); | |
| 4476 builtin_id = Builtins::STRING_ADD_LEFT; | |
| 4477 } | |
| 4478 | |
| 4479 // Both arguments are strings. | |
| 4480 // r0: first string | |
| 4481 // r1: second string | |
| 4482 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4483 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4484 { | |
| 4485 Label strings_not_empty; | |
| 4486 // Check if either of the strings are empty. In that case return the other. | |
| 4487 __ ldr(r2, FieldMemOperand(r0, String::kLengthOffset)); | |
| 4488 __ ldr(r3, FieldMemOperand(r1, String::kLengthOffset)); | |
| 4489 STATIC_ASSERT(kSmiTag == 0); | |
| 4490 __ cmp(r2, Operand(Smi::FromInt(0))); // Test if first string is empty. | |
| 4491 __ mov(r0, Operand(r1), LeaveCC, eq); // If first is empty, return second. | |
| 4492 STATIC_ASSERT(kSmiTag == 0); | |
| 4493 // Else test if second string is empty. | |
| 4494 __ cmp(r3, Operand(Smi::FromInt(0)), ne); | |
| 4495 __ b(ne, &strings_not_empty); // If either string was empty, return r0. | |
| 4496 | |
| 4497 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | |
| 4498 __ add(sp, sp, Operand(2 * kPointerSize)); | |
| 4499 __ Ret(); | |
| 4500 | |
| 4501 __ bind(&strings_not_empty); | |
| 4502 } | |
| 4503 | |
| 4504 __ SmiUntag(r2); | |
| 4505 __ SmiUntag(r3); | |
| 4506 // Both strings are non-empty. | |
| 4507 // r0: first string | |
| 4508 // r1: second string | |
| 4509 // r2: length of first string | |
| 4510 // r3: length of second string | |
| 4511 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4512 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4513 // Look at the length of the result of adding the two strings. | |
| 4514 Label string_add_flat_result, longer_than_two; | |
| 4515 // Adding two lengths can't overflow. | |
| 4516 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); | |
| 4517 __ add(r6, r2, Operand(r3)); | |
| 4518 // Use the string table when adding two one character strings, as it | |
| 4519 // helps later optimizations to return a string here. | |
| 4520 __ cmp(r6, Operand(2)); | |
| 4521 __ b(ne, &longer_than_two); | |
| 4522 | |
| 4523 // Check that both strings are non-external ASCII strings. | |
| 4524 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 4525 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
| 4526 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
| 4527 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | |
| 4528 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | |
| 4529 } | |
| 4530 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r3, | |
| 4531 &call_runtime); | |
| 4532 | |
| 4533 // Get the two characters forming the sub string. | |
| 4534 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); | |
| 4535 __ ldrb(r3, FieldMemOperand(r1, SeqOneByteString::kHeaderSize)); | |
| 4536 | |
| 4537 // Try to lookup two character string in string table. If it is not found | |
| 4538 // just allocate a new one. | |
| 4539 Label make_two_character_string; | |
| 4540 StringHelper::GenerateTwoCharacterStringTableProbe( | |
| 4541 masm, r2, r3, r6, r0, r4, r5, r9, &make_two_character_string); | |
| 4542 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | |
| 4543 __ add(sp, sp, Operand(2 * kPointerSize)); | |
| 4544 __ Ret(); | |
| 4545 | |
| 4546 __ bind(&make_two_character_string); | |
| 4547 // Resulting string has length 2 and first chars of two strings | |
| 4548 // are combined into single halfword in r2 register. | |
| 4549 // So we can fill resulting string without two loops by a single | |
| 4550 // halfword store instruction (which assumes that processor is | |
| 4551 // in a little endian mode) | |
| 4552 __ mov(r6, Operand(2)); | |
| 4553 __ AllocateAsciiString(r0, r6, r4, r5, r9, &call_runtime); | |
| 4554 __ strh(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); | |
| 4555 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | |
| 4556 __ add(sp, sp, Operand(2 * kPointerSize)); | |
| 4557 __ Ret(); | |
| 4558 | |
| 4559 __ bind(&longer_than_two); | |
| 4560 // Check if resulting string will be flat. | |
| 4561 __ cmp(r6, Operand(ConsString::kMinLength)); | |
| 4562 __ b(lt, &string_add_flat_result); | |
| 4563 // Handle exceptionally long strings in the runtime system. | |
| 4564 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | |
| 4565 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | |
| 4566 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | |
| 4567 __ cmp(r6, Operand(String::kMaxLength + 1)); | |
| 4568 __ b(hs, &call_runtime); | |
| 4569 | |
| 4570 // If result is not supposed to be flat, allocate a cons string object. | |
| 4571 // If both strings are ASCII the result is an ASCII cons string. | |
| 4572 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 4573 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
| 4574 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
| 4575 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | |
| 4576 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | |
| 4577 } | |
| 4578 Label non_ascii, allocated, ascii_data; | |
| 4579 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 4580 __ tst(r4, Operand(kStringEncodingMask)); | |
| 4581 __ tst(r5, Operand(kStringEncodingMask), ne); | |
| 4582 __ b(eq, &non_ascii); | |
| 4583 | |
| 4584 // Allocate an ASCII cons string. | |
| 4585 __ bind(&ascii_data); | |
| 4586 __ AllocateAsciiConsString(r3, r6, r4, r5, &call_runtime); | |
| 4587 __ bind(&allocated); | |
| 4588 // Fill the fields of the cons string. | |
| 4589 Label skip_write_barrier, after_writing; | |
| 4590 ExternalReference high_promotion_mode = ExternalReference:: | |
| 4591 new_space_high_promotion_mode_active_address(masm->isolate()); | |
| 4592 __ mov(r4, Operand(high_promotion_mode)); | |
| 4593 __ ldr(r4, MemOperand(r4, 0)); | |
| 4594 __ cmp(r4, Operand::Zero()); | |
| 4595 __ b(eq, &skip_write_barrier); | |
| 4596 | |
| 4597 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset)); | |
| 4598 __ RecordWriteField(r3, | |
| 4599 ConsString::kFirstOffset, | |
| 4600 r0, | |
| 4601 r4, | |
| 4602 kLRHasNotBeenSaved, | |
| 4603 kDontSaveFPRegs); | |
| 4604 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset)); | |
| 4605 __ RecordWriteField(r3, | |
| 4606 ConsString::kSecondOffset, | |
| 4607 r1, | |
| 4608 r4, | |
| 4609 kLRHasNotBeenSaved, | |
| 4610 kDontSaveFPRegs); | |
| 4611 __ jmp(&after_writing); | |
| 4612 | |
| 4613 __ bind(&skip_write_barrier); | |
| 4614 __ str(r0, FieldMemOperand(r3, ConsString::kFirstOffset)); | |
| 4615 __ str(r1, FieldMemOperand(r3, ConsString::kSecondOffset)); | |
| 4616 | |
| 4617 __ bind(&after_writing); | |
| 4618 | |
| 4619 __ mov(r0, Operand(r3)); | |
| 4620 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | |
| 4621 __ add(sp, sp, Operand(2 * kPointerSize)); | |
| 4622 __ Ret(); | |
| 4623 | |
| 4624 __ bind(&non_ascii); | |
| 4625 // At least one of the strings is two-byte. Check whether it happens | |
| 4626 // to contain only one byte characters. | |
| 4627 // r4: first instance type. | |
| 4628 // r5: second instance type. | |
| 4629 __ tst(r4, Operand(kOneByteDataHintMask)); | |
| 4630 __ tst(r5, Operand(kOneByteDataHintMask), ne); | |
| 4631 __ b(ne, &ascii_data); | |
| 4632 __ eor(r4, r4, Operand(r5)); | |
| 4633 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); | |
| 4634 __ and_(r4, r4, Operand(kOneByteStringTag | kOneByteDataHintTag)); | |
| 4635 __ cmp(r4, Operand(kOneByteStringTag | kOneByteDataHintTag)); | |
| 4636 __ b(eq, &ascii_data); | |
| 4637 | |
| 4638 // Allocate a two byte cons string. | |
| 4639 __ AllocateTwoByteConsString(r3, r6, r4, r5, &call_runtime); | |
| 4640 __ jmp(&allocated); | |
| 4641 | |
| 4642 // We cannot encounter sliced strings or cons strings here since: | |
| 4643 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); | |
| 4644 // Handle creating a flat result from either external or sequential strings. | |
| 4645 // Locate the first characters' locations. | |
| 4646 // r0: first string | |
| 4647 // r1: second string | |
| 4648 // r2: length of first string | |
| 4649 // r3: length of second string | |
| 4650 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4651 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | |
| 4652 // r6: sum of lengths. | |
| 4653 Label first_prepared, second_prepared; | |
| 4654 __ bind(&string_add_flat_result); | |
| 4655 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { | |
| 4656 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | |
| 4657 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
| 4658 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | |
| 4659 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | |
| 4660 } | |
| 4661 | |
| 4662 // Check whether both strings have same encoding | |
| 4663 __ eor(ip, r4, Operand(r5)); | |
| 4664 ASSERT(__ ImmediateFitsAddrMode1Instruction(kStringEncodingMask)); | |
| 4665 __ tst(ip, Operand(kStringEncodingMask)); | |
| 4666 __ b(ne, &call_runtime); | |
| 4667 | |
| 4668 STATIC_ASSERT(kSeqStringTag == 0); | |
| 4669 __ tst(r4, Operand(kStringRepresentationMask)); | |
| 4670 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 4671 __ add(r6, | |
| 4672 r0, | |
| 4673 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag), | |
| 4674 LeaveCC, | |
| 4675 eq); | |
| 4676 __ b(eq, &first_prepared); | |
| 4677 // External string: rule out short external string and load string resource. | |
| 4678 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 4679 __ tst(r4, Operand(kShortExternalStringMask)); | |
| 4680 __ b(ne, &call_runtime); | |
| 4681 __ ldr(r6, FieldMemOperand(r0, ExternalString::kResourceDataOffset)); | |
| 4682 __ bind(&first_prepared); | |
| 4683 | |
| 4684 STATIC_ASSERT(kSeqStringTag == 0); | |
| 4685 __ tst(r5, Operand(kStringRepresentationMask)); | |
| 4686 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 4687 __ add(r1, | |
| 4688 r1, | |
| 4689 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag), | |
| 4690 LeaveCC, | |
| 4691 eq); | |
| 4692 __ b(eq, &second_prepared); | |
| 4693 // External string: rule out short external string and load string resource. | |
| 4694 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 4695 __ tst(r5, Operand(kShortExternalStringMask)); | |
| 4696 __ b(ne, &call_runtime); | |
| 4697 __ ldr(r1, FieldMemOperand(r1, ExternalString::kResourceDataOffset)); | |
| 4698 __ bind(&second_prepared); | |
| 4699 | |
| 4700 Label non_ascii_string_add_flat_result; | |
| 4701 // r6: first character of first string | |
| 4702 // r1: first character of second string | |
| 4703 // r2: length of first string. | |
| 4704 // r3: length of second string. | |
| 4705 // Both strings have the same encoding. | |
| 4706 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 4707 __ tst(r5, Operand(kStringEncodingMask)); | |
| 4708 __ b(eq, &non_ascii_string_add_flat_result); | |
| 4709 | |
| 4710 __ add(r2, r2, Operand(r3)); | |
| 4711 __ AllocateAsciiString(r0, r2, r4, r5, r9, &call_runtime); | |
| 4712 __ sub(r2, r2, Operand(r3)); | |
| 4713 __ add(r5, r0, Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
| 4714 // r0: result string. | |
| 4715 // r6: first character of first string. | |
| 4716 // r1: first character of second string. | |
| 4717 // r2: length of first string. | |
| 4718 // r3: length of second string. | |
| 4719 // r5: first character of result. | |
| 4720 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, true); | |
| 4721 // r5: next character of result. | |
| 4722 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, true); | |
| 4723 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | |
| 4724 __ add(sp, sp, Operand(2 * kPointerSize)); | |
| 4725 __ Ret(); | |
| 4726 | |
| 4727 __ bind(&non_ascii_string_add_flat_result); | |
| 4728 __ add(r2, r2, Operand(r3)); | |
| 4729 __ AllocateTwoByteString(r0, r2, r4, r5, r9, &call_runtime); | |
| 4730 __ sub(r2, r2, Operand(r3)); | |
| 4731 __ add(r5, r0, Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
| 4732 // r0: result string. | |
| 4733 // r6: first character of first string. | |
| 4734 // r1: first character of second string. | |
| 4735 // r2: length of first string. | |
| 4736 // r3: length of second string. | |
| 4737 // r5: first character of result. | |
| 4738 StringHelper::GenerateCopyCharacters(masm, r5, r6, r2, r4, false); | |
| 4739 // r5: next character of result. | |
| 4740 StringHelper::GenerateCopyCharacters(masm, r5, r1, r3, r4, false); | |
| 4741 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | |
| 4742 __ add(sp, sp, Operand(2 * kPointerSize)); | |
| 4743 __ Ret(); | |
| 4744 | |
| 4745 // Just jump to runtime to add the two strings. | |
| 4746 __ bind(&call_runtime); | |
| 4747 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
| 4748 | |
| 4749 if (call_builtin.is_linked()) { | |
| 4750 __ bind(&call_builtin); | |
| 4751 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
| 4752 } | |
| 4753 } | |
| 4754 | |
| 4755 | |
| 4756 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
| 4757 __ push(r0); | |
| 4758 __ push(r1); | |
| 4759 } | |
| 4760 | |
| 4761 | |
| 4762 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm) { | |
| 4763 __ pop(r1); | |
| 4764 __ pop(r0); | |
| 4765 } | |
| 4766 | |
| 4767 | |
| 4768 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | |
| 4769 int stack_offset, | |
| 4770 Register arg, | |
| 4771 Register scratch1, | |
| 4772 Register scratch2, | |
| 4773 Register scratch3, | |
| 4774 Register scratch4, | |
| 4775 Label* slow) { | |
| 4776 // First check if the argument is already a string. | |
| 4777 Label not_string, done; | |
| 4778 __ JumpIfSmi(arg, ¬_string); | |
| 4779 __ CompareObjectType(arg, scratch1, scratch1, FIRST_NONSTRING_TYPE); | |
| 4780 __ b(lt, &done); | |
| 4781 | |
| 4782 // Check the number to string cache. | |
| 4783 __ bind(¬_string); | |
| 4784 // Puts the cached result into scratch1. | |
| 4785 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, scratch4, slow); | |
| 4786 __ mov(arg, scratch1); | |
| 4787 __ str(arg, MemOperand(sp, stack_offset)); | |
| 4788 __ bind(&done); | |
| 4789 } | |
| 4790 | |
| 4791 | |
| 4792 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 4269 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 4793 ASSERT(state_ == CompareIC::SMI); | 4270 ASSERT(state_ == CompareIC::SMI); |
| 4794 Label miss; | 4271 Label miss; |
| 4795 __ orr(r2, r1, r0); | 4272 __ orr(r2, r1, r0); |
| 4796 __ JumpIfNotSmi(r2, &miss); | 4273 __ JumpIfNotSmi(r2, &miss); |
| 4797 | 4274 |
| 4798 if (GetCondition() == eq) { | 4275 if (GetCondition() == eq) { |
| 4799 // For equality we do not care about the sign of the result. | 4276 // For equality we do not care about the sign of the result. |
| 4800 __ sub(r0, r0, r1, SetCC); | 4277 __ sub(r0, r0, r1, SetCC); |
| 4801 } else { | 4278 } else { |
| (...skipping 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6053 __ bind(&fast_elements_case); | 5530 __ bind(&fast_elements_case); |
| 6054 GenerateCase(masm, FAST_ELEMENTS); | 5531 GenerateCase(masm, FAST_ELEMENTS); |
| 6055 } | 5532 } |
| 6056 | 5533 |
| 6057 | 5534 |
| 6058 #undef __ | 5535 #undef __ |
| 6059 | 5536 |
| 6060 } } // namespace v8::internal | 5537 } } // namespace v8::internal |
| 6061 | 5538 |
| 6062 #endif // V8_TARGET_ARCH_ARM | 5539 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |