| 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 |