OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 3883 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3894 // non-zero value, which indicates not equal, so just return. | 3894 // non-zero value, which indicates not equal, so just return. |
3895 __ ret(0); | 3895 __ ret(0); |
3896 } | 3896 } |
3897 | 3897 |
3898 __ bind(&check_for_strings); | 3898 __ bind(&check_for_strings); |
3899 | 3899 |
3900 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, | 3900 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, |
3901 &check_unequal_objects); | 3901 &check_unequal_objects); |
3902 | 3902 |
3903 // Inline comparison of ascii strings. | 3903 // Inline comparison of ascii strings. |
3904 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, | 3904 if (cc_ == equal) { |
| 3905 StringCompareStub::GenerateFlatAsciiStringEquals(masm, |
3905 edx, | 3906 edx, |
3906 eax, | 3907 eax, |
3907 ecx, | 3908 ecx, |
3908 ebx, | 3909 ebx); |
3909 edi); | 3910 } else { |
| 3911 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, |
| 3912 edx, |
| 3913 eax, |
| 3914 ecx, |
| 3915 ebx, |
| 3916 edi); |
| 3917 } |
3910 #ifdef DEBUG | 3918 #ifdef DEBUG |
3911 __ Abort("Unexpected fall-through from string comparison"); | 3919 __ Abort("Unexpected fall-through from string comparison"); |
3912 #endif | 3920 #endif |
3913 | 3921 |
3914 __ bind(&check_unequal_objects); | 3922 __ bind(&check_unequal_objects); |
3915 if (cc_ == equal && !strict_) { | 3923 if (cc_ == equal && !strict_) { |
3916 // Non-strict equality. Objects are unequal if | 3924 // Non-strict equality. Objects are unequal if |
3917 // they are both JSObjects and not undetectable, | 3925 // they are both JSObjects and not undetectable, |
3918 // and their pointers are different. | 3926 // and their pointers are different. |
3919 NearLabel not_both_objects; | 3927 NearLabel not_both_objects; |
(...skipping 1675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5595 __ bind(&return_eax); | 5603 __ bind(&return_eax); |
5596 __ IncrementCounter(counters->sub_string_native(), 1); | 5604 __ IncrementCounter(counters->sub_string_native(), 1); |
5597 __ ret(3 * kPointerSize); | 5605 __ ret(3 * kPointerSize); |
5598 | 5606 |
5599 // Just jump to runtime to create the sub string. | 5607 // Just jump to runtime to create the sub string. |
5600 __ bind(&runtime); | 5608 __ bind(&runtime); |
5601 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 5609 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
5602 } | 5610 } |
5603 | 5611 |
5604 | 5612 |
| 5613 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, |
| 5614 Register left, |
| 5615 Register right, |
| 5616 Register scratch1, |
| 5617 Register scratch2) { |
| 5618 Register length = scratch1; |
| 5619 |
| 5620 // Compare lengths. |
| 5621 NearLabel strings_not_equal, check_zero_length; |
| 5622 __ mov(length, FieldOperand(left, String::kLengthOffset)); |
| 5623 __ cmp(length, FieldOperand(right, String::kLengthOffset)); |
| 5624 __ j(equal, &check_zero_length); |
| 5625 __ bind(&strings_not_equal); |
| 5626 __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); |
| 5627 __ ret(0); |
| 5628 |
| 5629 // Check if the length is zero. |
| 5630 NearLabel compare_chars; |
| 5631 __ bind(&check_zero_length); |
| 5632 STATIC_ASSERT(kSmiTag == 0); |
| 5633 __ test(length, Operand(length)); |
| 5634 __ j(not_zero, &compare_chars); |
| 5635 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 5636 __ ret(0); |
| 5637 |
| 5638 // Compare characters. |
| 5639 __ bind(&compare_chars); |
| 5640 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, |
| 5641 &strings_not_equal); |
| 5642 |
| 5643 // Characters are equal. |
| 5644 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 5645 __ ret(0); |
| 5646 } |
| 5647 |
| 5648 |
5605 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 5649 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
5606 Register left, | 5650 Register left, |
5607 Register right, | 5651 Register right, |
5608 Register scratch1, | 5652 Register scratch1, |
5609 Register scratch2, | 5653 Register scratch2, |
5610 Register scratch3) { | 5654 Register scratch3) { |
5611 Label result_not_equal; | |
5612 Label result_greater; | |
5613 Label compare_lengths; | |
5614 | |
5615 Counters* counters = masm->isolate()->counters(); | 5655 Counters* counters = masm->isolate()->counters(); |
5616 __ IncrementCounter(counters->string_compare_native(), 1); | 5656 __ IncrementCounter(counters->string_compare_native(), 1); |
5617 | 5657 |
5618 // Find minimum length. | 5658 // Find minimum length. |
5619 NearLabel left_shorter; | 5659 NearLabel left_shorter; |
5620 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 5660 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
5621 __ mov(scratch3, scratch1); | 5661 __ mov(scratch3, scratch1); |
5622 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); | 5662 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
5623 | 5663 |
5624 Register length_delta = scratch3; | 5664 Register length_delta = scratch3; |
5625 | 5665 |
5626 __ j(less_equal, &left_shorter); | 5666 __ j(less_equal, &left_shorter); |
5627 // Right string is shorter. Change scratch1 to be length of right string. | 5667 // Right string is shorter. Change scratch1 to be length of right string. |
5628 __ sub(scratch1, Operand(length_delta)); | 5668 __ sub(scratch1, Operand(length_delta)); |
5629 __ bind(&left_shorter); | 5669 __ bind(&left_shorter); |
5630 | 5670 |
5631 Register min_length = scratch1; | 5671 Register min_length = scratch1; |
5632 | 5672 |
5633 // If either length is zero, just compare lengths. | 5673 // If either length is zero, just compare lengths. |
| 5674 NearLabel compare_lengths; |
5634 __ test(min_length, Operand(min_length)); | 5675 __ test(min_length, Operand(min_length)); |
5635 __ j(zero, &compare_lengths); | 5676 __ j(zero, &compare_lengths); |
5636 | 5677 |
5637 // Change index to run from -min_length to -1 by adding min_length | 5678 // Compare characters. |
5638 // to string start. This means that loop ends when index reaches zero, | 5679 NearLabel result_not_equal; |
5639 // which doesn't need an additional compare. | 5680 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, |
5640 __ SmiUntag(min_length); | 5681 &result_not_equal); |
5641 __ lea(left, | |
5642 FieldOperand(left, | |
5643 min_length, times_1, | |
5644 SeqAsciiString::kHeaderSize)); | |
5645 __ lea(right, | |
5646 FieldOperand(right, | |
5647 min_length, times_1, | |
5648 SeqAsciiString::kHeaderSize)); | |
5649 __ neg(min_length); | |
5650 | |
5651 Register index = min_length; // index = -min_length; | |
5652 | |
5653 { | |
5654 // Compare loop. | |
5655 NearLabel loop; | |
5656 __ bind(&loop); | |
5657 // Compare characters. | |
5658 __ mov_b(scratch2, Operand(left, index, times_1, 0)); | |
5659 __ cmpb(scratch2, Operand(right, index, times_1, 0)); | |
5660 __ j(not_equal, &result_not_equal); | |
5661 __ add(Operand(index), Immediate(1)); | |
5662 __ j(not_zero, &loop); | |
5663 } | |
5664 | 5682 |
5665 // Compare lengths - strings up to min-length are equal. | 5683 // Compare lengths - strings up to min-length are equal. |
5666 __ bind(&compare_lengths); | 5684 __ bind(&compare_lengths); |
5667 __ test(length_delta, Operand(length_delta)); | 5685 __ test(length_delta, Operand(length_delta)); |
5668 __ j(not_zero, &result_not_equal); | 5686 __ j(not_zero, &result_not_equal); |
5669 | 5687 |
5670 // Result is EQUAL. | 5688 // Result is EQUAL. |
5671 STATIC_ASSERT(EQUAL == 0); | 5689 STATIC_ASSERT(EQUAL == 0); |
5672 STATIC_ASSERT(kSmiTag == 0); | 5690 STATIC_ASSERT(kSmiTag == 0); |
5673 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 5691 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
5674 __ ret(0); | 5692 __ ret(0); |
5675 | 5693 |
| 5694 NearLabel result_greater; |
5676 __ bind(&result_not_equal); | 5695 __ bind(&result_not_equal); |
5677 __ j(greater, &result_greater); | 5696 __ j(greater, &result_greater); |
5678 | 5697 |
5679 // Result is LESS. | 5698 // Result is LESS. |
5680 __ Set(eax, Immediate(Smi::FromInt(LESS))); | 5699 __ Set(eax, Immediate(Smi::FromInt(LESS))); |
5681 __ ret(0); | 5700 __ ret(0); |
5682 | 5701 |
5683 // Result is GREATER. | 5702 // Result is GREATER. |
5684 __ bind(&result_greater); | 5703 __ bind(&result_greater); |
5685 __ Set(eax, Immediate(Smi::FromInt(GREATER))); | 5704 __ Set(eax, Immediate(Smi::FromInt(GREATER))); |
5686 __ ret(0); | 5705 __ ret(0); |
5687 } | 5706 } |
5688 | 5707 |
5689 | 5708 |
| 5709 void StringCompareStub::GenerateAsciiCharsCompareLoop( |
| 5710 MacroAssembler* masm, |
| 5711 Register left, |
| 5712 Register right, |
| 5713 Register length, |
| 5714 Register scratch, |
| 5715 NearLabel* chars_not_equal) { |
| 5716 // Change index to run from -length to -1 by adding length to string |
| 5717 // start. This means that loop ends when index reaches zero, which |
| 5718 // doesn't need an additional compare. |
| 5719 __ SmiUntag(length); |
| 5720 __ lea(left, |
| 5721 FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); |
| 5722 __ lea(right, |
| 5723 FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); |
| 5724 __ neg(length); |
| 5725 Register index = length; // index = -length; |
| 5726 |
| 5727 // Compare loop. |
| 5728 NearLabel loop; |
| 5729 __ bind(&loop); |
| 5730 __ mov_b(scratch, Operand(left, index, times_1, 0)); |
| 5731 __ cmpb(scratch, Operand(right, index, times_1, 0)); |
| 5732 __ j(not_equal, chars_not_equal); |
| 5733 __ add(Operand(index), Immediate(1)); |
| 5734 __ j(not_zero, &loop); |
| 5735 } |
| 5736 |
| 5737 |
5690 void StringCompareStub::Generate(MacroAssembler* masm) { | 5738 void StringCompareStub::Generate(MacroAssembler* masm) { |
5691 Label runtime; | 5739 Label runtime; |
5692 | 5740 |
5693 // Stack frame on entry. | 5741 // Stack frame on entry. |
5694 // esp[0]: return address | 5742 // esp[0]: return address |
5695 // esp[4]: right string | 5743 // esp[4]: right string |
5696 // esp[8]: left string | 5744 // esp[8]: left string |
5697 | 5745 |
5698 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left | 5746 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left |
5699 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right | 5747 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5799 | 5847 |
5800 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); | 5848 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); |
5801 __ bind(&generic_stub); | 5849 __ bind(&generic_stub); |
5802 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); | 5850 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); |
5803 | 5851 |
5804 __ bind(&miss); | 5852 __ bind(&miss); |
5805 GenerateMiss(masm); | 5853 GenerateMiss(masm); |
5806 } | 5854 } |
5807 | 5855 |
5808 | 5856 |
| 5857 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { |
| 5858 ASSERT(state_ == CompareIC::STRINGS); |
| 5859 ASSERT(GetCondition() == equal); |
| 5860 Label miss; |
| 5861 |
| 5862 // Registers containing left and right operands respectively. |
| 5863 Register left = edx; |
| 5864 Register right = eax; |
| 5865 Register tmp1 = ecx; |
| 5866 Register tmp2 = ebx; |
| 5867 Register tmp3 = edi; |
| 5868 |
| 5869 // Check that both operands are heap objects. |
| 5870 __ mov(tmp1, Operand(left)); |
| 5871 STATIC_ASSERT(kSmiTag == 0); |
| 5872 __ and_(tmp1, Operand(right)); |
| 5873 __ test(tmp1, Immediate(kSmiTagMask)); |
| 5874 __ j(zero, &miss); |
| 5875 |
| 5876 // Check that both operands are strings. This leaves the instance |
| 5877 // types loaded in tmp1 and tmp2. |
| 5878 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); |
| 5879 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); |
| 5880 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5881 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5882 __ mov(tmp3, tmp1); |
| 5883 STATIC_ASSERT(kNotStringTag != 0); |
| 5884 __ or_(tmp3, Operand(tmp2)); |
| 5885 __ test(tmp3, Immediate(kIsNotStringMask)); |
| 5886 __ j(not_zero, &miss); |
| 5887 |
| 5888 // Fast check for identical strings. |
| 5889 NearLabel not_same; |
| 5890 __ cmp(left, Operand(right)); |
| 5891 __ j(not_equal, ¬_same); |
| 5892 STATIC_ASSERT(EQUAL == 0); |
| 5893 STATIC_ASSERT(kSmiTag == 0); |
| 5894 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 5895 __ ret(0); |
| 5896 |
| 5897 // Handle not identical strings. |
| 5898 __ bind(¬_same); |
| 5899 |
| 5900 // Check that both strings are symbols. If they are, we're done |
| 5901 // because we already know they are not identical. |
| 5902 NearLabel do_compare; |
| 5903 STATIC_ASSERT(kSymbolTag != 0); |
| 5904 __ and_(tmp1, Operand(tmp2)); |
| 5905 __ test(tmp1, Immediate(kIsSymbolMask)); |
| 5906 __ j(zero, &do_compare); |
| 5907 // Make sure eax is non-zero. At this point input operands are |
| 5908 // guaranteed to be non-zero. |
| 5909 ASSERT(right.is(eax)); |
| 5910 __ ret(0); |
| 5911 |
| 5912 // Check that both strings are sequential ASCII. |
| 5913 Label runtime; |
| 5914 __ bind(&do_compare); |
| 5915 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); |
| 5916 |
| 5917 // Compare flat ASCII strings. Returns when done. |
| 5918 StringCompareStub::GenerateFlatAsciiStringEquals( |
| 5919 masm, left, right, tmp1, tmp2); |
| 5920 |
| 5921 // Handle more complex cases in runtime. |
| 5922 __ bind(&runtime); |
| 5923 __ pop(tmp1); // Return address. |
| 5924 __ push(left); |
| 5925 __ push(right); |
| 5926 __ push(tmp1); |
| 5927 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); |
| 5928 |
| 5929 __ bind(&miss); |
| 5930 GenerateMiss(masm); |
| 5931 } |
| 5932 |
| 5933 |
5809 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { | 5934 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { |
5810 ASSERT(state_ == CompareIC::OBJECTS); | 5935 ASSERT(state_ == CompareIC::OBJECTS); |
5811 NearLabel miss; | 5936 NearLabel miss; |
5812 __ mov(ecx, Operand(edx)); | 5937 __ mov(ecx, Operand(edx)); |
5813 __ and_(ecx, Operand(eax)); | 5938 __ and_(ecx, Operand(eax)); |
5814 __ test(ecx, Immediate(kSmiTagMask)); | 5939 __ test(ecx, Immediate(kSmiTagMask)); |
5815 __ j(zero, &miss, not_taken); | 5940 __ j(zero, &miss, not_taken); |
5816 | 5941 |
5817 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); | 5942 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); |
5818 __ j(not_equal, &miss, not_taken); | 5943 __ j(not_equal, &miss, not_taken); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5852 __ pop(ecx); | 5977 __ pop(ecx); |
5853 __ pop(eax); | 5978 __ pop(eax); |
5854 __ pop(edx); | 5979 __ pop(edx); |
5855 __ push(ecx); | 5980 __ push(ecx); |
5856 | 5981 |
5857 // Do a tail call to the rewritten stub. | 5982 // Do a tail call to the rewritten stub. |
5858 __ jmp(Operand(edi)); | 5983 __ jmp(Operand(edi)); |
5859 } | 5984 } |
5860 | 5985 |
5861 | 5986 |
| 5987 // Helper function used to check that the dictionary doesn't contain |
| 5988 // the property. This function may return false negatives, so miss_label |
| 5989 // must always call a backup property check that is complete. |
| 5990 // This function is safe to call if the receiver has fast properties. |
| 5991 // Name must be a symbol and receiver must be a heap object. |
| 5992 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, |
| 5993 Label* miss, |
| 5994 Label* done, |
| 5995 Register properties, |
| 5996 String* name, |
| 5997 Register r0) { |
| 5998 ASSERT(name->IsSymbol()); |
| 5999 |
| 6000 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 6001 // not equal to the name and kProbes-th slot is not used (its name is the |
| 6002 // undefined value), it guarantees the hash table doesn't contain the |
| 6003 // property. It's true even if some slots represent deleted properties |
| 6004 // (their names are the null value). |
| 6005 for (int i = 0; i < kInlinedProbes; i++) { |
| 6006 // Compute the masked index: (hash + i + i * i) & mask. |
| 6007 Register index = r0; |
| 6008 // Capacity is smi 2^n. |
| 6009 __ mov(index, FieldOperand(properties, kCapacityOffset)); |
| 6010 __ dec(index); |
| 6011 __ and_(Operand(index), |
| 6012 Immediate(Smi::FromInt(name->Hash() + |
| 6013 StringDictionary::GetProbeOffset(i)))); |
| 6014 |
| 6015 // Scale the index by multiplying by the entry size. |
| 6016 ASSERT(StringDictionary::kEntrySize == 3); |
| 6017 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 6018 Register entity_name = r0; |
| 6019 // Having undefined at this place means the name is not contained. |
| 6020 ASSERT_EQ(kSmiTagSize, 1); |
| 6021 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
| 6022 kElementsStartOffset - kHeapObjectTag)); |
| 6023 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
| 6024 __ j(equal, done, taken); |
| 6025 |
| 6026 // Stop if found the property. |
| 6027 __ cmp(entity_name, Handle<String>(name)); |
| 6028 __ j(equal, miss, not_taken); |
| 6029 |
| 6030 // Check if the entry name is not a symbol. |
| 6031 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 6032 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 6033 kIsSymbolMask); |
| 6034 __ j(zero, miss, not_taken); |
| 6035 } |
| 6036 |
| 6037 StringDictionaryLookupStub stub(properties, |
| 6038 r0, |
| 6039 r0, |
| 6040 StringDictionaryLookupStub::NEGATIVE_LOOKUP); |
| 6041 __ push(Immediate(Handle<Object>(name))); |
| 6042 __ push(Immediate(name->Hash())); |
| 6043 __ CallStub(&stub); |
| 6044 __ test(r0, Operand(r0)); |
| 6045 __ j(not_zero, miss); |
| 6046 __ jmp(done); |
| 6047 } |
| 6048 |
| 6049 |
| 6050 // Probe the string dictionary in the |elements| register. Jump to the |
| 6051 // |done| label if a property with the given name is found leaving the |
| 6052 // index into the dictionary in |r0|. Jump to the |miss| label |
| 6053 // otherwise. |
| 6054 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, |
| 6055 Label* miss, |
| 6056 Label* done, |
| 6057 Register elements, |
| 6058 Register name, |
| 6059 Register r0, |
| 6060 Register r1) { |
| 6061 // Assert that name contains a string. |
| 6062 if (FLAG_debug_code) __ AbortIfNotString(name); |
| 6063 |
| 6064 __ mov(r1, FieldOperand(elements, kCapacityOffset)); |
| 6065 __ shr(r1, kSmiTagSize); // convert smi to int |
| 6066 __ dec(r1); |
| 6067 |
| 6068 // Generate an unrolled loop that performs a few probes before |
| 6069 // giving up. Measurements done on Gmail indicate that 2 probes |
| 6070 // cover ~93% of loads from dictionaries. |
| 6071 for (int i = 0; i < kInlinedProbes; i++) { |
| 6072 // Compute the masked index: (hash + i + i * i) & mask. |
| 6073 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |
| 6074 __ shr(r0, String::kHashShift); |
| 6075 if (i > 0) { |
| 6076 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); |
| 6077 } |
| 6078 __ and_(r0, Operand(r1)); |
| 6079 |
| 6080 // Scale the index by multiplying by the entry size. |
| 6081 ASSERT(StringDictionary::kEntrySize == 3); |
| 6082 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 |
| 6083 |
| 6084 // Check if the key is identical to the name. |
| 6085 __ cmp(name, Operand(elements, |
| 6086 r0, |
| 6087 times_4, |
| 6088 kElementsStartOffset - kHeapObjectTag)); |
| 6089 __ j(equal, done, taken); |
| 6090 } |
| 6091 |
| 6092 StringDictionaryLookupStub stub(elements, |
| 6093 r1, |
| 6094 r0, |
| 6095 POSITIVE_LOOKUP); |
| 6096 __ push(name); |
| 6097 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |
| 6098 __ shr(r0, String::kHashShift); |
| 6099 __ push(r0); |
| 6100 __ CallStub(&stub); |
| 6101 |
| 6102 __ test(r1, Operand(r1)); |
| 6103 __ j(zero, miss); |
| 6104 __ jmp(done); |
| 6105 } |
| 6106 |
| 6107 |
| 6108 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |
| 6109 // Stack frame on entry: |
| 6110 // esp[0 * kPointerSize]: return address. |
| 6111 // esp[1 * kPointerSize]: key's hash. |
| 6112 // esp[2 * kPointerSize]: key. |
| 6113 // Registers: |
| 6114 // dictionary_: StringDictionary to probe. |
| 6115 // result_: used as scratch. |
| 6116 // index_: will hold an index of entry if lookup is successful. |
| 6117 // might alias with result_. |
| 6118 // Returns: |
| 6119 // result_ is zero if lookup failed, non zero otherwise. |
| 6120 |
| 6121 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
| 6122 |
| 6123 Register scratch = result_; |
| 6124 |
| 6125 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); |
| 6126 __ dec(scratch); |
| 6127 __ SmiUntag(scratch); |
| 6128 __ push(scratch); |
| 6129 |
| 6130 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 6131 // not equal to the name and kProbes-th slot is not used (its name is the |
| 6132 // undefined value), it guarantees the hash table doesn't contain the |
| 6133 // property. It's true even if some slots represent deleted properties |
| 6134 // (their names are the null value). |
| 6135 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 6136 // Compute the masked index: (hash + i + i * i) & mask. |
| 6137 __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| 6138 if (i > 0) { |
| 6139 __ add(Operand(scratch), |
| 6140 Immediate(StringDictionary::GetProbeOffset(i))); |
| 6141 } |
| 6142 __ and_(scratch, Operand(esp, 0)); |
| 6143 |
| 6144 // Scale the index by multiplying by the entry size. |
| 6145 ASSERT(StringDictionary::kEntrySize == 3); |
| 6146 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. |
| 6147 |
| 6148 // Having undefined at this place means the name is not contained. |
| 6149 ASSERT_EQ(kSmiTagSize, 1); |
| 6150 __ mov(scratch, Operand(dictionary_, |
| 6151 index_, |
| 6152 times_pointer_size, |
| 6153 kElementsStartOffset - kHeapObjectTag)); |
| 6154 __ cmp(scratch, masm->isolate()->factory()->undefined_value()); |
| 6155 __ j(equal, ¬_in_dictionary); |
| 6156 |
| 6157 // Stop if found the property. |
| 6158 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); |
| 6159 __ j(equal, &in_dictionary); |
| 6160 |
| 6161 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 6162 // If we hit a non symbol key during negative lookup |
| 6163 // we have to bailout as this key might be equal to the |
| 6164 // key we are looking for. |
| 6165 |
| 6166 // Check if the entry name is not a symbol. |
| 6167 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 6168 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 6169 kIsSymbolMask); |
| 6170 __ j(zero, &maybe_in_dictionary); |
| 6171 } |
| 6172 } |
| 6173 |
| 6174 __ bind(&maybe_in_dictionary); |
| 6175 // If we are doing negative lookup then probing failure should be |
| 6176 // treated as a lookup success. For positive lookup probing failure |
| 6177 // should be treated as lookup failure. |
| 6178 if (mode_ == POSITIVE_LOOKUP) { |
| 6179 __ mov(result_, Immediate(0)); |
| 6180 __ Drop(1); |
| 6181 __ ret(2 * kPointerSize); |
| 6182 } |
| 6183 |
| 6184 __ bind(&in_dictionary); |
| 6185 __ mov(result_, Immediate(1)); |
| 6186 __ Drop(1); |
| 6187 __ ret(2 * kPointerSize); |
| 6188 |
| 6189 __ bind(¬_in_dictionary); |
| 6190 __ mov(result_, Immediate(0)); |
| 6191 __ Drop(1); |
| 6192 __ ret(2 * kPointerSize); |
| 6193 } |
| 6194 |
| 6195 |
5862 #undef __ | 6196 #undef __ |
5863 | 6197 |
5864 } } // namespace v8::internal | 6198 } } // namespace v8::internal |
5865 | 6199 |
5866 #endif // V8_TARGET_ARCH_IA32 | 6200 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |