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