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 7089 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7100 | 7100 |
7101 // Do a tail call to the rewritten stub. | 7101 // Do a tail call to the rewritten stub. |
7102 __ jmp(edi); | 7102 __ jmp(edi); |
7103 } | 7103 } |
7104 | 7104 |
7105 | 7105 |
7106 // Helper function used to check that the dictionary doesn't contain | 7106 // Helper function used to check that the dictionary doesn't contain |
7107 // the property. This function may return false negatives, so miss_label | 7107 // the property. This function may return false negatives, so miss_label |
7108 // must always call a backup property check that is complete. | 7108 // must always call a backup property check that is complete. |
7109 // This function is safe to call if the receiver has fast properties. | 7109 // This function is safe to call if the receiver has fast properties. |
7110 // Name must be an internalized string and receiver must be a heap object. | 7110 // Name must be a unique name and receiver must be a heap object. |
7111 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, | 7111 void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, |
7112 Label* miss, | 7112 Label* miss, |
7113 Label* done, | 7113 Label* done, |
7114 Register properties, | 7114 Register properties, |
7115 Handle<String> name, | 7115 Handle<Name> name, |
7116 Register r0) { | 7116 Register r0) { |
7117 ASSERT(name->IsInternalizedString()); | 7117 ASSERT(name->IsUniqueName()); |
7118 | 7118 |
7119 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 7119 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
7120 // not equal to the name and kProbes-th slot is not used (its name is the | 7120 // not equal to the name and kProbes-th slot is not used (its name is the |
7121 // undefined value), it guarantees the hash table doesn't contain the | 7121 // undefined value), it guarantees the hash table doesn't contain the |
7122 // property. It's true even if some slots represent deleted properties | 7122 // property. It's true even if some slots represent deleted properties |
7123 // (their names are the hole value). | 7123 // (their names are the hole value). |
7124 for (int i = 0; i < kInlinedProbes; i++) { | 7124 for (int i = 0; i < kInlinedProbes; i++) { |
7125 // Compute the masked index: (hash + i + i * i) & mask. | 7125 // Compute the masked index: (hash + i + i * i) & mask. |
7126 Register index = r0; | 7126 Register index = r0; |
7127 // Capacity is smi 2^n. | 7127 // Capacity is smi 2^n. |
7128 __ mov(index, FieldOperand(properties, kCapacityOffset)); | 7128 __ mov(index, FieldOperand(properties, kCapacityOffset)); |
7129 __ dec(index); | 7129 __ dec(index); |
7130 __ and_(index, | 7130 __ and_(index, |
7131 Immediate(Smi::FromInt(name->Hash() + | 7131 Immediate(Smi::FromInt(name->Hash() + |
7132 StringDictionary::GetProbeOffset(i)))); | 7132 NameDictionary::GetProbeOffset(i)))); |
7133 | 7133 |
7134 // Scale the index by multiplying by the entry size. | 7134 // Scale the index by multiplying by the entry size. |
7135 ASSERT(StringDictionary::kEntrySize == 3); | 7135 ASSERT(NameDictionary::kEntrySize == 3); |
7136 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. | 7136 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
7137 Register entity_name = r0; | 7137 Register entity_name = r0; |
7138 // Having undefined at this place means the name is not contained. | 7138 // Having undefined at this place means the name is not contained. |
7139 ASSERT_EQ(kSmiTagSize, 1); | 7139 ASSERT_EQ(kSmiTagSize, 1); |
7140 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, | 7140 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
7141 kElementsStartOffset - kHeapObjectTag)); | 7141 kElementsStartOffset - kHeapObjectTag)); |
7142 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); | 7142 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
7143 __ j(equal, done); | 7143 __ j(equal, done); |
7144 | 7144 |
7145 // Stop if found the property. | 7145 // Stop if found the property. |
7146 __ cmp(entity_name, Handle<String>(name)); | 7146 __ cmp(entity_name, Handle<Name>(name)); |
7147 __ j(equal, miss); | 7147 __ j(equal, miss); |
7148 | 7148 |
7149 Label the_hole; | 7149 Label good; |
7150 // Check for the hole and skip. | 7150 // Check for the hole and skip. |
7151 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); | 7151 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); |
7152 __ j(equal, &the_hole, Label::kNear); | 7152 __ j(equal, &good, Label::kNear); |
7153 | 7153 |
7154 // Check if the entry name is not an internalized string. | 7154 // Check if the entry name is not a unique name. |
7155 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); | 7155 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
7156 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), | 7156 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
7157 kIsInternalizedMask); | 7157 kIsInternalizedMask); |
7158 __ j(zero, miss); | 7158 __ j(not_zero, &good); |
7159 __ bind(&the_hole); | 7159 __ cmpb(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 7160 static_cast<int8_t>(SYMBOL_TYPE)); |
| 7161 __ j(not_equal, miss); |
| 7162 __ bind(&good); |
7160 } | 7163 } |
7161 | 7164 |
7162 StringDictionaryLookupStub stub(properties, | 7165 NameDictionaryLookupStub stub(properties, r0, r0, NEGATIVE_LOOKUP); |
7163 r0, | |
7164 r0, | |
7165 StringDictionaryLookupStub::NEGATIVE_LOOKUP); | |
7166 __ push(Immediate(Handle<Object>(name))); | 7166 __ push(Immediate(Handle<Object>(name))); |
7167 __ push(Immediate(name->Hash())); | 7167 __ push(Immediate(name->Hash())); |
7168 __ CallStub(&stub); | 7168 __ CallStub(&stub); |
7169 __ test(r0, r0); | 7169 __ test(r0, r0); |
7170 __ j(not_zero, miss); | 7170 __ j(not_zero, miss); |
7171 __ jmp(done); | 7171 __ jmp(done); |
7172 } | 7172 } |
7173 | 7173 |
7174 | 7174 |
7175 // Probe the string dictionary in the |elements| register. Jump to the | 7175 // Probe the name dictionary in the |elements| register. Jump to the |
7176 // |done| label if a property with the given name is found leaving the | 7176 // |done| label if a property with the given name is found leaving the |
7177 // index into the dictionary in |r0|. Jump to the |miss| label | 7177 // index into the dictionary in |r0|. Jump to the |miss| label |
7178 // otherwise. | 7178 // otherwise. |
7179 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, | 7179 void NameDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, |
7180 Label* miss, | 7180 Label* miss, |
7181 Label* done, | 7181 Label* done, |
7182 Register elements, | 7182 Register elements, |
7183 Register name, | 7183 Register name, |
7184 Register r0, | 7184 Register r0, |
7185 Register r1) { | 7185 Register r1) { |
7186 ASSERT(!elements.is(r0)); | 7186 ASSERT(!elements.is(r0)); |
7187 ASSERT(!elements.is(r1)); | 7187 ASSERT(!elements.is(r1)); |
7188 ASSERT(!name.is(r0)); | 7188 ASSERT(!name.is(r0)); |
7189 ASSERT(!name.is(r1)); | 7189 ASSERT(!name.is(r1)); |
7190 | 7190 |
7191 __ AssertString(name); | 7191 __ AssertName(name); |
7192 | 7192 |
7193 __ mov(r1, FieldOperand(elements, kCapacityOffset)); | 7193 __ mov(r1, FieldOperand(elements, kCapacityOffset)); |
7194 __ shr(r1, kSmiTagSize); // convert smi to int | 7194 __ shr(r1, kSmiTagSize); // convert smi to int |
7195 __ dec(r1); | 7195 __ dec(r1); |
7196 | 7196 |
7197 // Generate an unrolled loop that performs a few probes before | 7197 // Generate an unrolled loop that performs a few probes before |
7198 // giving up. Measurements done on Gmail indicate that 2 probes | 7198 // giving up. Measurements done on Gmail indicate that 2 probes |
7199 // cover ~93% of loads from dictionaries. | 7199 // cover ~93% of loads from dictionaries. |
7200 for (int i = 0; i < kInlinedProbes; i++) { | 7200 for (int i = 0; i < kInlinedProbes; i++) { |
7201 // Compute the masked index: (hash + i + i * i) & mask. | 7201 // Compute the masked index: (hash + i + i * i) & mask. |
7202 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); | 7202 __ mov(r0, FieldOperand(name, Name::kHashFieldOffset)); |
7203 __ shr(r0, String::kHashShift); | 7203 __ shr(r0, Name::kHashShift); |
7204 if (i > 0) { | 7204 if (i > 0) { |
7205 __ add(r0, Immediate(StringDictionary::GetProbeOffset(i))); | 7205 __ add(r0, Immediate(NameDictionary::GetProbeOffset(i))); |
7206 } | 7206 } |
7207 __ and_(r0, r1); | 7207 __ and_(r0, r1); |
7208 | 7208 |
7209 // Scale the index by multiplying by the entry size. | 7209 // Scale the index by multiplying by the entry size. |
7210 ASSERT(StringDictionary::kEntrySize == 3); | 7210 ASSERT(NameDictionary::kEntrySize == 3); |
7211 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 | 7211 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 |
7212 | 7212 |
7213 // Check if the key is identical to the name. | 7213 // Check if the key is identical to the name. |
7214 __ cmp(name, Operand(elements, | 7214 __ cmp(name, Operand(elements, |
7215 r0, | 7215 r0, |
7216 times_4, | 7216 times_4, |
7217 kElementsStartOffset - kHeapObjectTag)); | 7217 kElementsStartOffset - kHeapObjectTag)); |
7218 __ j(equal, done); | 7218 __ j(equal, done); |
7219 } | 7219 } |
7220 | 7220 |
7221 StringDictionaryLookupStub stub(elements, | 7221 NameDictionaryLookupStub stub(elements, r1, r0, POSITIVE_LOOKUP); |
7222 r1, | |
7223 r0, | |
7224 POSITIVE_LOOKUP); | |
7225 __ push(name); | 7222 __ push(name); |
7226 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); | 7223 __ mov(r0, FieldOperand(name, Name::kHashFieldOffset)); |
7227 __ shr(r0, String::kHashShift); | 7224 __ shr(r0, Name::kHashShift); |
7228 __ push(r0); | 7225 __ push(r0); |
7229 __ CallStub(&stub); | 7226 __ CallStub(&stub); |
7230 | 7227 |
7231 __ test(r1, r1); | 7228 __ test(r1, r1); |
7232 __ j(zero, miss); | 7229 __ j(zero, miss); |
7233 __ jmp(done); | 7230 __ jmp(done); |
7234 } | 7231 } |
7235 | 7232 |
7236 | 7233 |
7237 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { | 7234 void NameDictionaryLookupStub::Generate(MacroAssembler* masm) { |
7238 // This stub overrides SometimesSetsUpAFrame() to return false. That means | 7235 // This stub overrides SometimesSetsUpAFrame() to return false. That means |
7239 // we cannot call anything that could cause a GC from this stub. | 7236 // we cannot call anything that could cause a GC from this stub. |
7240 // Stack frame on entry: | 7237 // Stack frame on entry: |
7241 // esp[0 * kPointerSize]: return address. | 7238 // esp[0 * kPointerSize]: return address. |
7242 // esp[1 * kPointerSize]: key's hash. | 7239 // esp[1 * kPointerSize]: key's hash. |
7243 // esp[2 * kPointerSize]: key. | 7240 // esp[2 * kPointerSize]: key. |
7244 // Registers: | 7241 // Registers: |
7245 // dictionary_: StringDictionary to probe. | 7242 // dictionary_: NameDictionary to probe. |
7246 // result_: used as scratch. | 7243 // result_: used as scratch. |
7247 // index_: will hold an index of entry if lookup is successful. | 7244 // index_: will hold an index of entry if lookup is successful. |
7248 // might alias with result_. | 7245 // might alias with result_. |
7249 // Returns: | 7246 // Returns: |
7250 // result_ is zero if lookup failed, non zero otherwise. | 7247 // result_ is zero if lookup failed, non zero otherwise. |
7251 | 7248 |
7252 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; | 7249 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; |
7253 | 7250 |
7254 Register scratch = result_; | 7251 Register scratch = result_; |
7255 | 7252 |
7256 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); | 7253 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); |
7257 __ dec(scratch); | 7254 __ dec(scratch); |
7258 __ SmiUntag(scratch); | 7255 __ SmiUntag(scratch); |
7259 __ push(scratch); | 7256 __ push(scratch); |
7260 | 7257 |
7261 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 7258 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
7262 // not equal to the name and kProbes-th slot is not used (its name is the | 7259 // not equal to the name and kProbes-th slot is not used (its name is the |
7263 // undefined value), it guarantees the hash table doesn't contain the | 7260 // undefined value), it guarantees the hash table doesn't contain the |
7264 // property. It's true even if some slots represent deleted properties | 7261 // property. It's true even if some slots represent deleted properties |
7265 // (their names are the null value). | 7262 // (their names are the null value). |
7266 for (int i = kInlinedProbes; i < kTotalProbes; i++) { | 7263 for (int i = kInlinedProbes; i < kTotalProbes; i++) { |
7267 // Compute the masked index: (hash + i + i * i) & mask. | 7264 // Compute the masked index: (hash + i + i * i) & mask. |
7268 __ mov(scratch, Operand(esp, 2 * kPointerSize)); | 7265 __ mov(scratch, Operand(esp, 2 * kPointerSize)); |
7269 if (i > 0) { | 7266 if (i > 0) { |
7270 __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i))); | 7267 __ add(scratch, Immediate(NameDictionary::GetProbeOffset(i))); |
7271 } | 7268 } |
7272 __ and_(scratch, Operand(esp, 0)); | 7269 __ and_(scratch, Operand(esp, 0)); |
7273 | 7270 |
7274 // Scale the index by multiplying by the entry size. | 7271 // Scale the index by multiplying by the entry size. |
7275 ASSERT(StringDictionary::kEntrySize == 3); | 7272 ASSERT(NameDictionary::kEntrySize == 3); |
7276 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. | 7273 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. |
7277 | 7274 |
7278 // Having undefined at this place means the name is not contained. | 7275 // Having undefined at this place means the name is not contained. |
7279 ASSERT_EQ(kSmiTagSize, 1); | 7276 ASSERT_EQ(kSmiTagSize, 1); |
7280 __ mov(scratch, Operand(dictionary_, | 7277 __ mov(scratch, Operand(dictionary_, |
7281 index_, | 7278 index_, |
7282 times_pointer_size, | 7279 times_pointer_size, |
7283 kElementsStartOffset - kHeapObjectTag)); | 7280 kElementsStartOffset - kHeapObjectTag)); |
7284 __ cmp(scratch, masm->isolate()->factory()->undefined_value()); | 7281 __ cmp(scratch, masm->isolate()->factory()->undefined_value()); |
7285 __ j(equal, ¬_in_dictionary); | 7282 __ j(equal, ¬_in_dictionary); |
7286 | 7283 |
7287 // Stop if found the property. | 7284 // Stop if found the property. |
7288 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); | 7285 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); |
7289 __ j(equal, &in_dictionary); | 7286 __ j(equal, &in_dictionary); |
7290 | 7287 |
7291 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { | 7288 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { |
7292 // If we hit a key that is not an internalized string during negative | 7289 // If we hit a key that is not a unique name during negative |
7293 // lookup we have to bailout as this key might be equal to the | 7290 // lookup we have to bailout as this key might be equal to the |
7294 // key we are looking for. | 7291 // key we are looking for. |
7295 | 7292 |
7296 // Check if the entry name is not an internalized string. | 7293 // Check if the entry name is not a unique name. |
| 7294 Label cont; |
7297 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 7295 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
7298 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), | 7296 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), |
7299 kIsInternalizedMask); | 7297 kIsInternalizedMask); |
7300 __ j(zero, &maybe_in_dictionary); | 7298 __ j(not_zero, &cont); |
| 7299 __ cmpb(FieldOperand(scratch, Map::kInstanceTypeOffset), |
| 7300 static_cast<int8_t>(SYMBOL_TYPE)); |
| 7301 __ j(not_equal, &maybe_in_dictionary); |
| 7302 __ bind(&cont); |
7301 } | 7303 } |
7302 } | 7304 } |
7303 | 7305 |
7304 __ bind(&maybe_in_dictionary); | 7306 __ bind(&maybe_in_dictionary); |
7305 // If we are doing negative lookup then probing failure should be | 7307 // If we are doing negative lookup then probing failure should be |
7306 // treated as a lookup success. For positive lookup probing failure | 7308 // treated as a lookup success. For positive lookup probing failure |
7307 // should be treated as lookup failure. | 7309 // should be treated as lookup failure. |
7308 if (mode_ == POSITIVE_LOOKUP) { | 7310 if (mode_ == POSITIVE_LOOKUP) { |
7309 __ mov(result_, Immediate(0)); | 7311 __ mov(result_, Immediate(0)); |
7310 __ Drop(1); | 7312 __ Drop(1); |
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7744 // Restore ecx. | 7746 // Restore ecx. |
7745 __ pop(ecx); | 7747 __ pop(ecx); |
7746 __ ret(0); | 7748 __ ret(0); |
7747 } | 7749 } |
7748 | 7750 |
7749 #undef __ | 7751 #undef __ |
7750 | 7752 |
7751 } } // namespace v8::internal | 7753 } } // namespace v8::internal |
7752 | 7754 |
7753 #endif // V8_TARGET_ARCH_IA32 | 7755 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |