OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
54 __ j(equal, global_object); | 54 __ j(equal, global_object); |
55 __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE)); | 55 __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE)); |
56 __ j(equal, global_object); | 56 __ j(equal, global_object); |
57 __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE)); | 57 __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE)); |
58 __ j(equal, global_object); | 58 __ j(equal, global_object); |
59 } | 59 } |
60 | 60 |
61 | 61 |
62 // Generated code falls through if the receiver is a regular non-global | 62 // Generated code falls through if the receiver is a regular non-global |
63 // JS object with slow properties and no interceptors. | 63 // JS object with slow properties and no interceptors. |
64 static void GenerateDictionaryLoadReceiverCheck(MacroAssembler* masm, | 64 static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm, |
65 Register receiver, | 65 Register receiver, |
66 Register r0, | 66 Register r0, |
67 Register r1, | 67 Register r1, |
68 Label* miss) { | 68 Label* miss) { |
69 // Register usage: | 69 // Register usage: |
70 // receiver: holds the receiver on entry and is unchanged. | 70 // receiver: holds the receiver on entry and is unchanged. |
71 // r0: used to hold receiver instance type. | 71 // r0: used to hold receiver instance type. |
72 // Holds the property dictionary on fall through. | 72 // Holds the property dictionary on fall through. |
73 // r1: used to hold receivers map. | 73 // r1: used to hold receivers map. |
74 | 74 |
75 __ JumpIfSmi(receiver, miss); | 75 __ JumpIfSmi(receiver, miss); |
76 | 76 |
77 // Check that the receiver is a valid JS object. | 77 // Check that the receiver is a valid JS object. |
78 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset)); | 78 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset)); |
(...skipping 12 matching lines...) Expand all Loading... |
91 (1 << Map::kHasNamedInterceptor))); | 91 (1 << Map::kHasNamedInterceptor))); |
92 __ j(not_zero, miss); | 92 __ j(not_zero, miss); |
93 | 93 |
94 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 94 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
95 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset), | 95 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset), |
96 Heap::kHashTableMapRootIndex); | 96 Heap::kHashTableMapRootIndex); |
97 __ j(not_equal, miss); | 97 __ j(not_equal, miss); |
98 } | 98 } |
99 | 99 |
100 | 100 |
101 // Helper function used to load a property from a dictionary backing storage. | 101 // Probe the string dictionary in the |elements| register. Jump to the |
102 // This function may return false negatives, so miss_label | 102 // |done| label if a property with the given name is found leaving the |
103 // must always call a backup property load that is complete. | 103 // index into the dictionary in |r1|. Jump to the |miss| label |
104 // This function is safe to call if name is not a symbol, and will jump to | 104 // otherwise. |
105 // the miss_label in that case. | 105 static void GenerateStringDictionaryProbes(MacroAssembler* masm, |
106 // The generated code assumes that the receiver has slow properties, | 106 Label* miss, |
107 // is not a global object and does not have interceptors. | 107 Label* done, |
108 static void GenerateDictionaryLoad(MacroAssembler* masm, | 108 Register elements, |
109 Label* miss_label, | 109 Register name, |
110 Register elements, | 110 Register r0, |
111 Register name, | 111 Register r1) { |
112 Register r0, | |
113 Register r1, | |
114 Register result) { | |
115 // Register use: | |
116 // | |
117 // elements - holds the property dictionary on entry and is unchanged. | |
118 // | |
119 // name - holds the name of the property on entry and is unchanged. | |
120 // | |
121 // r0 - used to hold the capacity of the property dictionary. | |
122 // | |
123 // r1 - used to hold the index into the property dictionary. | |
124 // | |
125 // result - holds the result on exit if the load succeeded. | |
126 | |
127 Label done; | |
128 | |
129 // Compute the capacity mask. | 112 // Compute the capacity mask. |
130 const int kCapacityOffset = | 113 const int kCapacityOffset = |
131 StringDictionary::kHeaderSize + | 114 StringDictionary::kHeaderSize + |
132 StringDictionary::kCapacityIndex * kPointerSize; | 115 StringDictionary::kCapacityIndex * kPointerSize; |
133 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); | 116 __ SmiToInteger32(r0, FieldOperand(elements, kCapacityOffset)); |
134 __ decl(r0); | 117 __ decl(r0); |
135 | 118 |
136 // Generate an unrolled loop that performs a few probes before | 119 // Generate an unrolled loop that performs a few probes before |
137 // giving up. Measurements done on Gmail indicate that 2 probes | 120 // giving up. Measurements done on Gmail indicate that 2 probes |
138 // cover ~93% of loads from dictionaries. | 121 // cover ~93% of loads from dictionaries. |
(...skipping 11 matching lines...) Expand all Loading... |
150 __ and_(r1, r0); | 133 __ and_(r1, r0); |
151 | 134 |
152 // Scale the index by multiplying by the entry size. | 135 // Scale the index by multiplying by the entry size. |
153 ASSERT(StringDictionary::kEntrySize == 3); | 136 ASSERT(StringDictionary::kEntrySize == 3); |
154 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 | 137 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3 |
155 | 138 |
156 // Check if the key is identical to the name. | 139 // Check if the key is identical to the name. |
157 __ cmpq(name, Operand(elements, r1, times_pointer_size, | 140 __ cmpq(name, Operand(elements, r1, times_pointer_size, |
158 kElementsStartOffset - kHeapObjectTag)); | 141 kElementsStartOffset - kHeapObjectTag)); |
159 if (i != kProbes - 1) { | 142 if (i != kProbes - 1) { |
160 __ j(equal, &done); | 143 __ j(equal, done); |
161 } else { | 144 } else { |
162 __ j(not_equal, miss_label); | 145 __ j(not_equal, miss); |
163 } | 146 } |
164 } | 147 } |
| 148 } |
165 | 149 |
166 // Check that the value is a normal property. | 150 |
| 151 // Helper function used to load a property from a dictionary backing storage. |
| 152 // This function may return false negatives, so miss_label |
| 153 // must always call a backup property load that is complete. |
| 154 // This function is safe to call if name is not a symbol, and will jump to |
| 155 // the miss_label in that case. |
| 156 // The generated code assumes that the receiver has slow properties, |
| 157 // is not a global object and does not have interceptors. |
| 158 static void GenerateDictionaryLoad(MacroAssembler* masm, |
| 159 Label* miss_label, |
| 160 Register elements, |
| 161 Register name, |
| 162 Register r0, |
| 163 Register r1, |
| 164 Register result) { |
| 165 // Register use: |
| 166 // |
| 167 // elements - holds the property dictionary on entry and is unchanged. |
| 168 // |
| 169 // name - holds the name of the property on entry and is unchanged. |
| 170 // |
| 171 // r0 - used to hold the capacity of the property dictionary. |
| 172 // |
| 173 // r1 - used to hold the index into the property dictionary. |
| 174 // |
| 175 // result - holds the result on exit if the load succeeded. |
| 176 |
| 177 Label done; |
| 178 |
| 179 // Probe the dictionary. |
| 180 GenerateStringDictionaryProbes(masm, |
| 181 miss_label, |
| 182 &done, |
| 183 elements, |
| 184 name, |
| 185 r0, |
| 186 r1); |
| 187 |
| 188 // If probing finds an entry in the dictionary, r0 contains the |
| 189 // index into the dictionary. Check that the value is a normal |
| 190 // property. |
167 __ bind(&done); | 191 __ bind(&done); |
| 192 const int kElementsStartOffset = |
| 193 StringDictionary::kHeaderSize + |
| 194 StringDictionary::kElementsStartIndex * kPointerSize; |
168 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | 195 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
169 __ Test(Operand(elements, r1, times_pointer_size, | 196 __ Test(Operand(elements, r1, times_pointer_size, |
170 kDetailsOffset - kHeapObjectTag), | 197 kDetailsOffset - kHeapObjectTag), |
171 Smi::FromInt(PropertyDetails::TypeField::mask())); | 198 Smi::FromInt(PropertyDetails::TypeField::mask())); |
172 __ j(not_zero, miss_label); | 199 __ j(not_zero, miss_label); |
173 | 200 |
174 // Get the value at the masked, scaled index. | 201 // Get the value at the masked, scaled index. |
175 const int kValueOffset = kElementsStartOffset + kPointerSize; | 202 const int kValueOffset = kElementsStartOffset + kPointerSize; |
176 __ movq(result, | 203 __ movq(result, |
177 Operand(elements, r1, times_pointer_size, | 204 Operand(elements, r1, times_pointer_size, |
178 kValueOffset - kHeapObjectTag)); | 205 kValueOffset - kHeapObjectTag)); |
179 } | 206 } |
180 | 207 |
181 | 208 |
| 209 // Helper function used to store a property to a dictionary backing |
| 210 // storage. This function may fail to store a property even though it |
| 211 // is in the dictionary, so code at miss_label must always call a |
| 212 // backup property store that is complete. This function is safe to |
| 213 // call if name is not a symbol, and will jump to the miss_label in |
| 214 // that case. The generated code assumes that the receiver has slow |
| 215 // properties, is not a global object and does not have interceptors. |
| 216 static void GenerateDictionaryStore(MacroAssembler* masm, |
| 217 Label* miss_label, |
| 218 Register elements, |
| 219 Register name, |
| 220 Register value, |
| 221 Register scratch0, |
| 222 Register scratch1) { |
| 223 // Register use: |
| 224 // |
| 225 // elements - holds the property dictionary on entry and is clobbered. |
| 226 // |
| 227 // name - holds the name of the property on entry and is unchanged. |
| 228 // |
| 229 // value - holds the value to store and is unchanged. |
| 230 // |
| 231 // scratch0 - used for index into the property dictionary and is clobbered. |
| 232 // |
| 233 // scratch1 - used to hold the capacity of the property dictionary and is |
| 234 // clobbered. |
| 235 Label done; |
| 236 |
| 237 // Probe the dictionary. |
| 238 GenerateStringDictionaryProbes(masm, |
| 239 miss_label, |
| 240 &done, |
| 241 elements, |
| 242 name, |
| 243 scratch0, |
| 244 scratch1); |
| 245 |
| 246 // If probing finds an entry in the dictionary, scratch0 contains the |
| 247 // index into the dictionary. Check that the value is a normal |
| 248 // property that is not read only. |
| 249 __ bind(&done); |
| 250 const int kElementsStartOffset = |
| 251 StringDictionary::kHeaderSize + |
| 252 StringDictionary::kElementsStartIndex * kPointerSize; |
| 253 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; |
| 254 const int kTypeAndReadOnlyMask |
| 255 = (PropertyDetails::TypeField::mask() | |
| 256 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize; |
| 257 __ Test(Operand(elements, |
| 258 scratch1, |
| 259 times_pointer_size, |
| 260 kDetailsOffset - kHeapObjectTag), |
| 261 Smi::FromInt(kTypeAndReadOnlyMask)); |
| 262 __ j(not_zero, miss_label); |
| 263 |
| 264 // Store the value at the masked, scaled index. |
| 265 const int kValueOffset = kElementsStartOffset + kPointerSize; |
| 266 __ lea(scratch1, Operand(elements, |
| 267 scratch1, |
| 268 times_pointer_size, |
| 269 kValueOffset - kHeapObjectTag)); |
| 270 __ movq(Operand(scratch1, 0), value); |
| 271 |
| 272 // Update write barrier. Make sure not to clobber the value. |
| 273 __ movq(scratch0, value); |
| 274 __ RecordWrite(elements, scratch1, scratch0); |
| 275 } |
| 276 |
| 277 |
182 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 278 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
183 Label* miss, | 279 Label* miss, |
184 Register elements, | 280 Register elements, |
185 Register key, | 281 Register key, |
186 Register r0, | 282 Register r0, |
187 Register r1, | 283 Register r1, |
188 Register r2, | 284 Register r2, |
189 Register result) { | 285 Register result) { |
190 // Register use: | 286 // Register use: |
191 // | 287 // |
(...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1325 // rsp[16] : argument argc - 1 | 1421 // rsp[16] : argument argc - 1 |
1326 // ... | 1422 // ... |
1327 // rsp[argc * 8] : argument 1 | 1423 // rsp[argc * 8] : argument 1 |
1328 // rsp[(argc + 1) * 8] : argument 0 = receiver | 1424 // rsp[(argc + 1) * 8] : argument 0 = receiver |
1329 // ----------------------------------- | 1425 // ----------------------------------- |
1330 Label miss; | 1426 Label miss; |
1331 | 1427 |
1332 // Get the receiver of the function from the stack. | 1428 // Get the receiver of the function from the stack. |
1333 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 1429 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
1334 | 1430 |
1335 GenerateDictionaryLoadReceiverCheck(masm, rdx, rax, rbx, &miss); | 1431 GenerateStringDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss); |
1336 | 1432 |
1337 // rax: elements | 1433 // rax: elements |
1338 // Search the dictionary placing the result in rdi. | 1434 // Search the dictionary placing the result in rdi. |
1339 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi); | 1435 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi); |
1340 | 1436 |
1341 GenerateFunctionTailCall(masm, argc, &miss); | 1437 GenerateFunctionTailCall(masm, argc, &miss); |
1342 | 1438 |
1343 __ bind(&miss); | 1439 __ bind(&miss); |
1344 } | 1440 } |
1345 | 1441 |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1609 | 1705 |
1610 | 1706 |
1611 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 1707 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
1612 // ----------- S t a t e ------------- | 1708 // ----------- S t a t e ------------- |
1613 // -- rax : receiver | 1709 // -- rax : receiver |
1614 // -- rcx : name | 1710 // -- rcx : name |
1615 // -- rsp[0] : return address | 1711 // -- rsp[0] : return address |
1616 // ----------------------------------- | 1712 // ----------------------------------- |
1617 Label miss; | 1713 Label miss; |
1618 | 1714 |
1619 GenerateDictionaryLoadReceiverCheck(masm, rax, rdx, rbx, &miss); | 1715 GenerateStringDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss); |
1620 | 1716 |
1621 // rdx: elements | 1717 // rdx: elements |
1622 // Search the dictionary placing the result in rax. | 1718 // Search the dictionary placing the result in rax. |
1623 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax); | 1719 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax); |
1624 __ ret(0); | 1720 __ ret(0); |
1625 | 1721 |
1626 // Cache miss: Jump to runtime. | 1722 // Cache miss: Jump to runtime. |
1627 __ bind(&miss); | 1723 __ bind(&miss); |
1628 GenerateMiss(masm); | 1724 GenerateMiss(masm); |
1629 } | 1725 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1753 | 1849 |
1754 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength)); | 1850 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength)); |
1755 __ TailCallExternalReference(ref, 2, 1); | 1851 __ TailCallExternalReference(ref, 2, 1); |
1756 | 1852 |
1757 __ bind(&miss); | 1853 __ bind(&miss); |
1758 | 1854 |
1759 GenerateMiss(masm); | 1855 GenerateMiss(masm); |
1760 } | 1856 } |
1761 | 1857 |
1762 | 1858 |
| 1859 void StoreIC::GenerateNormal(MacroAssembler* masm) { |
| 1860 // ----------- S t a t e ------------- |
| 1861 // -- rax : value |
| 1862 // -- rcx : name |
| 1863 // -- rdx : receiver |
| 1864 // -- rsp[0] : return address |
| 1865 // ----------------------------------- |
| 1866 |
| 1867 Label miss, restore_miss; |
| 1868 |
| 1869 GenerateStringDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss); |
| 1870 |
| 1871 GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9); |
| 1872 __ IncrementCounter(&Counters::store_normal_hit, 1); |
| 1873 __ ret(0); |
| 1874 |
| 1875 __ bind(&miss); |
| 1876 __ IncrementCounter(&Counters::store_normal_miss, 1); |
| 1877 GenerateMiss(masm); |
| 1878 } |
| 1879 |
| 1880 |
1763 #undef __ | 1881 #undef __ |
1764 | 1882 |
1765 | 1883 |
1766 } } // namespace v8::internal | 1884 } } // namespace v8::internal |
1767 | 1885 |
1768 #endif // V8_TARGET_ARCH_X64 | 1886 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |