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 5841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5852 __ pop(ecx); | 5852 __ pop(ecx); |
5853 __ pop(eax); | 5853 __ pop(eax); |
5854 __ pop(edx); | 5854 __ pop(edx); |
5855 __ push(ecx); | 5855 __ push(ecx); |
5856 | 5856 |
5857 // Do a tail call to the rewritten stub. | 5857 // Do a tail call to the rewritten stub. |
5858 __ jmp(Operand(edi)); | 5858 __ jmp(Operand(edi)); |
5859 } | 5859 } |
5860 | 5860 |
5861 | 5861 |
| 5862 // Helper function used to check that the dictionary doesn't contain |
| 5863 // the property. This function may return false negatives, so miss_label |
| 5864 // must always call a backup property check that is complete. |
| 5865 // This function is safe to call if the receiver has fast properties. |
| 5866 // Name must be a symbol and receiver must be a heap object. |
| 5867 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, |
| 5868 Label* miss, |
| 5869 Label* done, |
| 5870 Register properties, |
| 5871 String* name, |
| 5872 Register r0) { |
| 5873 ASSERT(name->IsSymbol()); |
| 5874 |
| 5875 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 5876 // not equal to the name and kProbes-th slot is not used (its name is the |
| 5877 // undefined value), it guarantees the hash table doesn't contain the |
| 5878 // property. It's true even if some slots represent deleted properties |
| 5879 // (their names are the null value). |
| 5880 for (int i = 0; i < kInlinedProbes; i++) { |
| 5881 // Compute the masked index: (hash + i + i * i) & mask. |
| 5882 Register index = r0; |
| 5883 // Capacity is smi 2^n. |
| 5884 __ mov(index, FieldOperand(properties, kCapacityOffset)); |
| 5885 __ dec(index); |
| 5886 __ and_(Operand(index), |
| 5887 Immediate(Smi::FromInt(name->Hash() + |
| 5888 StringDictionary::GetProbeOffset(i)))); |
| 5889 |
| 5890 // Scale the index by multiplying by the entry size. |
| 5891 ASSERT(StringDictionary::kEntrySize == 3); |
| 5892 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 5893 Register entity_name = r0; |
| 5894 // Having undefined at this place means the name is not contained. |
| 5895 ASSERT_EQ(kSmiTagSize, 1); |
| 5896 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
| 5897 kElementsStartOffset - kHeapObjectTag)); |
| 5898 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
| 5899 __ j(equal, done, taken); |
| 5900 |
| 5901 // Stop if found the property. |
| 5902 __ cmp(entity_name, Handle<String>(name)); |
| 5903 __ j(equal, miss, not_taken); |
| 5904 |
| 5905 // Check if the entry name is not a symbol. |
| 5906 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 5907 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 5908 kIsSymbolMask); |
| 5909 __ j(zero, miss, not_taken); |
| 5910 } |
| 5911 |
| 5912 StringDictionaryLookupStub stub(properties, |
| 5913 r0, |
| 5914 r0, |
| 5915 StringDictionaryLookupStub::NEGATIVE_LOOKUP); |
| 5916 __ push(Immediate(Handle<Object>(name))); |
| 5917 __ push(Immediate(name->Hash())); |
| 5918 __ CallStub(&stub); |
| 5919 __ test(r0, Operand(r0)); |
| 5920 __ j(not_zero, miss); |
| 5921 __ jmp(done); |
| 5922 } |
| 5923 |
| 5924 |
| 5925 // Probe the string dictionary in the |elements| register. Jump to the |
| 5926 // |done| label if a property with the given name is found leaving the |
| 5927 // index into the dictionary in |r0|. Jump to the |miss| label |
| 5928 // otherwise. |
| 5929 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, |
| 5930 Label* miss, |
| 5931 Label* done, |
| 5932 Register elements, |
| 5933 Register name, |
| 5934 Register r0, |
| 5935 Register r1) { |
| 5936 // Assert that name contains a string. |
| 5937 if (FLAG_debug_code) __ AbortIfNotString(name); |
| 5938 |
| 5939 __ mov(r1, FieldOperand(elements, kCapacityOffset)); |
| 5940 __ shr(r1, kSmiTagSize); // convert smi to int |
| 5941 __ dec(r1); |
| 5942 |
| 5943 // Generate an unrolled loop that performs a few probes before |
| 5944 // giving up. Measurements done on Gmail indicate that 2 probes |
| 5945 // cover ~93% of loads from dictionaries. |
| 5946 for (int i = 0; i < kInlinedProbes; i++) { |
| 5947 // Compute the masked index: (hash + i + i * i) & mask. |
| 5948 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |
| 5949 __ shr(r0, String::kHashShift); |
| 5950 if (i > 0) { |
| 5951 __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i))); |
| 5952 } |
| 5953 __ and_(r0, Operand(r1)); |
| 5954 |
| 5955 // Scale the index by multiplying by the entry size. |
| 5956 ASSERT(StringDictionary::kEntrySize == 3); |
| 5957 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 |
| 5958 |
| 5959 // Check if the key is identical to the name. |
| 5960 __ cmp(name, Operand(elements, |
| 5961 r0, |
| 5962 times_4, |
| 5963 kElementsStartOffset - kHeapObjectTag)); |
| 5964 __ j(equal, done, taken); |
| 5965 } |
| 5966 |
| 5967 StringDictionaryLookupStub stub(elements, |
| 5968 r1, |
| 5969 r0, |
| 5970 POSITIVE_LOOKUP); |
| 5971 __ push(name); |
| 5972 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); |
| 5973 __ shr(r0, String::kHashShift); |
| 5974 __ push(r0); |
| 5975 __ CallStub(&stub); |
| 5976 |
| 5977 __ test(r1, Operand(r1)); |
| 5978 __ j(zero, miss); |
| 5979 __ jmp(done); |
| 5980 } |
| 5981 |
| 5982 |
| 5983 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { |
| 5984 // Stack frame on entry: |
| 5985 // esp[0 * kPointerSize]: return address. |
| 5986 // esp[1 * kPointerSize]: key's hash. |
| 5987 // esp[2 * kPointerSize]: key. |
| 5988 // Registers: |
| 5989 // dictionary_: StringDictionary to probe. |
| 5990 // result_: used as scratch. |
| 5991 // index_: will hold an index of entry if lookup is successful. |
| 5992 // might alias with result_. |
| 5993 // Returns: |
| 5994 // result_ is zero if lookup failed, non zero otherwise. |
| 5995 |
| 5996 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
| 5997 |
| 5998 Register scratch = result_; |
| 5999 |
| 6000 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); |
| 6001 __ dec(scratch); |
| 6002 __ SmiUntag(scratch); |
| 6003 __ push(scratch); |
| 6004 |
| 6005 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 6006 // not equal to the name and kProbes-th slot is not used (its name is the |
| 6007 // undefined value), it guarantees the hash table doesn't contain the |
| 6008 // property. It's true even if some slots represent deleted properties |
| 6009 // (their names are the null value). |
| 6010 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
| 6011 // Compute the masked index: (hash + i + i * i) & mask. |
| 6012 __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
| 6013 if (i > 0) { |
| 6014 __ add(Operand(scratch), |
| 6015 Immediate(StringDictionary::GetProbeOffset(i))); |
| 6016 } |
| 6017 __ and_(scratch, Operand(esp, 0)); |
| 6018 |
| 6019 // Scale the index by multiplying by the entry size. |
| 6020 ASSERT(StringDictionary::kEntrySize == 3); |
| 6021 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. |
| 6022 |
| 6023 // Having undefined at this place means the name is not contained. |
| 6024 ASSERT_EQ(kSmiTagSize, 1); |
| 6025 __ mov(scratch, Operand(dictionary_, |
| 6026 index_, |
| 6027 times_pointer_size, |
| 6028 kElementsStartOffset - kHeapObjectTag)); |
| 6029 __ cmp(scratch, masm->isolate()->factory()->undefined_value()); |
| 6030 __ j(equal, ¬_in_dictionary); |
| 6031 |
| 6032 // Stop if found the property. |
| 6033 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); |
| 6034 __ j(equal, &in_dictionary); |
| 6035 |
| 6036 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
| 6037 // If we hit a non symbol key during negative lookup |
| 6038 // we have to bailout as this key might be equal to the |
| 6039 // key we are looking for. |
| 6040 |
| 6041 // Check if the entry name is not a symbol. |
| 6042 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 6043 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 6044 kIsSymbolMask); |
| 6045 __ j(zero, &maybe_in_dictionary); |
| 6046 } |
| 6047 } |
| 6048 |
| 6049 __ bind(&maybe_in_dictionary); |
| 6050 // If we are doing negative lookup then probing failure should be |
| 6051 // treated as a lookup success. For positive lookup probing failure |
| 6052 // should be treated as lookup failure. |
| 6053 if (mode_ == POSITIVE_LOOKUP) { |
| 6054 __ mov(result_, Immediate(0)); |
| 6055 __ Drop(1); |
| 6056 __ ret(2 * kPointerSize); |
| 6057 } |
| 6058 |
| 6059 __ bind(&in_dictionary); |
| 6060 __ mov(result_, Immediate(1)); |
| 6061 __ Drop(1); |
| 6062 __ ret(2 * kPointerSize); |
| 6063 |
| 6064 __ bind(¬_in_dictionary); |
| 6065 __ mov(result_, Immediate(0)); |
| 6066 __ Drop(1); |
| 6067 __ ret(2 * kPointerSize); |
| 6068 } |
| 6069 |
| 6070 |
5862 #undef __ | 6071 #undef __ |
5863 | 6072 |
5864 } } // namespace v8::internal | 6073 } } // namespace v8::internal |
5865 | 6074 |
5866 #endif // V8_TARGET_ARCH_IA32 | 6075 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |