OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 Register key, | 154 Register key, |
155 Register t0, | 155 Register t0, |
156 Register t1, | 156 Register t1, |
157 Register t2) { | 157 Register t2) { |
158 // Register use: | 158 // Register use: |
159 // | 159 // |
160 // elements - holds the slow-case elements of the receiver and is unchanged. | 160 // elements - holds the slow-case elements of the receiver and is unchanged. |
161 // | 161 // |
162 // key - holds the smi key on entry and is unchanged if a branch is | 162 // key - holds the smi key on entry and is unchanged if a branch is |
163 // performed to the miss label. | 163 // performed to the miss label. |
| 164 // Holds the result on exit if the load succeeded. |
164 // | 165 // |
165 // Scratch registers: | 166 // Scratch registers: |
166 // | 167 // |
167 // t0 - holds the untagged key on entry and holds the hash once computed. | 168 // t0 - holds the untagged key on entry and holds the hash once computed. |
168 // Holds the result on exit if the load succeeded. | |
169 // | 169 // |
170 // t1 - used to hold the capacity mask of the dictionary | 170 // t1 - used to hold the capacity mask of the dictionary |
171 // | 171 // |
172 // t2 - used for the index into the dictionary. | 172 // t2 - used for the index into the dictionary. |
173 Label done; | 173 Label done; |
174 | 174 |
175 // Compute the hash code from the untagged key. This must be kept in sync | 175 // Compute the hash code from the untagged key. This must be kept in sync |
176 // with ComputeIntegerHash in utils.h. | 176 // with ComputeIntegerHash in utils.h. |
177 // | 177 // |
178 // hash = ~hash + (hash << 15); | 178 // hash = ~hash + (hash << 15); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
226 // t2: elements + (index * kPointerSize) | 226 // t2: elements + (index * kPointerSize) |
227 const int kDetailsOffset = | 227 const int kDetailsOffset = |
228 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; | 228 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
229 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset)); | 229 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset)); |
230 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); | 230 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); |
231 __ b(ne, miss); | 231 __ b(ne, miss); |
232 | 232 |
233 // Get the value at the masked, scaled index and return. | 233 // Get the value at the masked, scaled index and return. |
234 const int kValueOffset = | 234 const int kValueOffset = |
235 NumberDictionary::kElementsStartOffset + kPointerSize; | 235 NumberDictionary::kElementsStartOffset + kPointerSize; |
236 __ ldr(t0, FieldMemOperand(t2, kValueOffset)); | 236 __ ldr(key, FieldMemOperand(t2, kValueOffset)); |
237 } | 237 } |
238 | 238 |
239 | 239 |
240 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 240 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
241 // ----------- S t a t e ------------- | 241 // ----------- S t a t e ------------- |
242 // -- r2 : name | 242 // -- r2 : name |
243 // -- lr : return address | 243 // -- lr : return address |
244 // -- r0 : receiver | 244 // -- r0 : receiver |
245 // -- sp[0] : receiver | 245 // -- sp[0] : receiver |
246 // ----------------------------------- | 246 // ----------------------------------- |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
732 // In the case that the object is a value-wrapper object, | 732 // In the case that the object is a value-wrapper object, |
733 // we enter the runtime system to make sure that indexing into string | 733 // we enter the runtime system to make sure that indexing into string |
734 // objects work as intended. | 734 // objects work as intended. |
735 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 735 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
736 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 736 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
737 __ cmp(r2, Operand(JS_OBJECT_TYPE)); | 737 __ cmp(r2, Operand(JS_OBJECT_TYPE)); |
738 __ b(lt, &slow); | 738 __ b(lt, &slow); |
739 | 739 |
740 // Check that the key is a smi. | 740 // Check that the key is a smi. |
741 __ BranchOnNotSmi(key, &slow); | 741 __ BranchOnNotSmi(key, &slow); |
742 // Untag key into r2.. | |
743 __ mov(r2, Operand(key, ASR, kSmiTagSize)); | |
744 | |
745 // Get the elements array of the object. | 742 // Get the elements array of the object. |
746 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 743 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
747 // Check that the object is in fast mode (not dictionary). | 744 // Check that the object is in fast mode (not dictionary). |
748 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); | 745 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); |
749 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 746 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
750 __ cmp(r3, ip); | 747 __ cmp(r3, ip); |
751 __ b(ne, &check_pixel_array); | 748 __ b(ne, &check_pixel_array); |
752 // Check that the key (index) is within bounds. | 749 // Check that the key (index) is within bounds. |
753 __ ldr(r3, FieldMemOperand(r4, Array::kLengthOffset)); | 750 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); |
754 __ cmp(r2, r3); | 751 __ cmp(key, Operand(r3)); |
755 __ b(hs, &slow); | 752 __ b(hs, &slow); |
756 // Fast case: Do the load. | 753 // Fast case: Do the load. |
757 __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 754 __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
758 __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2)); | 755 // The key is a smi. |
| 756 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 757 __ ldr(r2, MemOperand(r3, key, LSL, kPointerSizeLog2 - kSmiTagSize)); |
759 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 758 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
760 __ cmp(r2, ip); | 759 __ cmp(r2, ip); |
761 // In case the loaded value is the_hole we have to consult GetProperty | 760 // In case the loaded value is the_hole we have to consult GetProperty |
762 // to ensure the prototype chain is searched. | 761 // to ensure the prototype chain is searched. |
763 __ b(eq, &slow); | 762 __ b(eq, &slow); |
764 __ mov(r0, r2); | 763 __ mov(r0, r2); |
765 __ Ret(); | 764 __ Ret(); |
766 | 765 |
767 // Check whether the elements is a pixel array. | 766 // Check whether the elements is a pixel array. |
768 // r0: key | 767 // r0: key |
769 // r2: untagged index | |
770 // r3: elements map | 768 // r3: elements map |
771 // r4: elements | 769 // r4: elements |
772 __ bind(&check_pixel_array); | 770 __ bind(&check_pixel_array); |
773 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); | 771 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); |
774 __ cmp(r3, ip); | 772 __ cmp(r3, ip); |
775 __ b(ne, &check_number_dictionary); | 773 __ b(ne, &check_number_dictionary); |
776 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset)); | 774 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset)); |
| 775 __ mov(r2, Operand(key, ASR, kSmiTagSize)); |
777 __ cmp(r2, ip); | 776 __ cmp(r2, ip); |
778 __ b(hs, &slow); | 777 __ b(hs, &slow); |
779 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset)); | 778 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset)); |
780 __ ldrb(r2, MemOperand(ip, r2)); | 779 __ ldrb(r2, MemOperand(ip, r2)); |
781 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi. | 780 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi. |
782 __ Ret(); | 781 __ Ret(); |
783 | 782 |
784 __ bind(&check_number_dictionary); | 783 __ bind(&check_number_dictionary); |
785 // Check whether the elements is a number dictionary. | 784 // Check whether the elements is a number dictionary. |
786 // r0: key | 785 // r0: key |
787 // r2: untagged index | |
788 // r3: elements map | 786 // r3: elements map |
789 // r4: elements | 787 // r4: elements |
790 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 788 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
791 __ cmp(r3, ip); | 789 __ cmp(r3, ip); |
792 __ b(ne, &slow); | 790 __ b(ne, &slow); |
| 791 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); |
793 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5); | 792 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5); |
794 __ mov(r0, r2); | |
795 __ Ret(); | 793 __ Ret(); |
796 | 794 |
797 // Slow case, key and receiver still in r0 and r1. | 795 // Slow case, key and receiver still in r0 and r1. |
798 __ bind(&slow); | 796 __ bind(&slow); |
799 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); | 797 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); |
800 GenerateRuntimeGetProperty(masm); | 798 GenerateRuntimeGetProperty(masm); |
801 } | 799 } |
802 | 800 |
803 | 801 |
804 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 802 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1268 __ b(lt, &slow); | 1266 __ b(lt, &slow); |
1269 | 1267 |
1270 | 1268 |
1271 // Object case: Check key against length in the elements array. | 1269 // Object case: Check key against length in the elements array. |
1272 __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset)); | 1270 __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset)); |
1273 // Check that the object is in fast mode (not dictionary). | 1271 // Check that the object is in fast mode (not dictionary). |
1274 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); | 1272 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); |
1275 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 1273 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
1276 __ cmp(r2, ip); | 1274 __ cmp(r2, ip); |
1277 __ b(ne, &check_pixel_array); | 1275 __ b(ne, &check_pixel_array); |
1278 // Untag the key (for checking against untagged length in the fixed array). | |
1279 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); | |
1280 // Compute address to store into and check array bounds. | 1276 // Compute address to store into and check array bounds. |
1281 __ add(r2, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1277 __ add(r2, r3, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
1282 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); | 1278 // The key is a smi. Assert we can shift left by 1 to use it as a |
| 1279 // byte offset. |
| 1280 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
| 1281 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
1283 __ ldr(ip, FieldMemOperand(r3, FixedArray::kLengthOffset)); | 1282 __ ldr(ip, FieldMemOperand(r3, FixedArray::kLengthOffset)); |
1284 __ cmp(r1, Operand(ip)); | 1283 __ cmp(r1, Operand(ip)); |
1285 __ b(lo, &fast); | 1284 __ b(lo, &fast); |
1286 | 1285 |
1287 | 1286 |
1288 // Slow case: | 1287 // Slow case: |
1289 __ bind(&slow); | 1288 __ bind(&slow); |
1290 GenerateRuntimeSetProperty(masm); | 1289 GenerateRuntimeSetProperty(masm); |
1291 | 1290 |
1292 // Check whether the elements is a pixel array. | 1291 // Check whether the elements is a pixel array. |
(...skipping 26 matching lines...) Expand all Loading... |
1319 __ mov(r0, Operand(r4)); // Return the original value. | 1318 __ mov(r0, Operand(r4)); // Return the original value. |
1320 __ Ret(); | 1319 __ Ret(); |
1321 | 1320 |
1322 | 1321 |
1323 // Extra capacity case: Check if there is extra capacity to | 1322 // Extra capacity case: Check if there is extra capacity to |
1324 // perform the store and update the length. Used for adding one | 1323 // perform the store and update the length. Used for adding one |
1325 // element to the array by writing to array[array.length]. | 1324 // element to the array by writing to array[array.length]. |
1326 // r0 == value, r1 == key, r2 == elements, r3 == object | 1325 // r0 == value, r1 == key, r2 == elements, r3 == object |
1327 __ bind(&extra); | 1326 __ bind(&extra); |
1328 __ b(ne, &slow); // do not leave holes in the array | 1327 __ b(ne, &slow); // do not leave holes in the array |
1329 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag | 1328 __ ldr(ip, FieldMemOperand(r2, FixedArray::kLengthOffset)); |
1330 __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset)); | |
1331 __ cmp(r1, Operand(ip)); | 1329 __ cmp(r1, Operand(ip)); |
1332 __ b(hs, &slow); | 1330 __ b(hs, &slow); |
1333 __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag | 1331 // Increment the key to get the new length. |
1334 __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment | 1332 __ add(r1, r1, Operand(Smi::FromInt(1))); |
1335 __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset)); | 1333 __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset)); |
1336 __ mov(r3, Operand(r2)); | 1334 __ mov(r3, Operand(r2)); |
1337 // NOTE: Computing the address to store into must take the fact | 1335 // NOTE: Computing the address to store into must take the fact |
1338 // that the key has been incremented into account. | 1336 // that the key has been incremented into account. |
1339 int displacement = FixedArray::kHeaderSize - kHeapObjectTag - | 1337 int displacement = FixedArray::kHeaderSize - kHeapObjectTag - |
1340 ((1 << kSmiTagSize) * 2); | 1338 ((1 << kSmiTagSize) * 2); |
1341 __ add(r2, r2, Operand(displacement)); | 1339 __ add(r2, r2, Operand(displacement)); |
| 1340 // The key is a smi. Assert we can shift left by 1 to use it as a |
| 1341 // byte offset. |
| 1342 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
1342 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); | 1343 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
1343 __ b(&fast); | 1344 __ b(&fast); |
1344 | 1345 |
1345 | 1346 |
1346 // Array case: Get the length and the elements array from the JS | 1347 // Array case: Get the length and the elements array from the JS |
1347 // array. Check that the array is in fast mode; if it is the | 1348 // array. Check that the array is in fast mode; if it is the |
1348 // length is always a smi. | 1349 // length is always a smi. |
1349 // r0 == value, r3 == object | 1350 // r0 == value, r3 == object |
1350 __ bind(&array); | 1351 __ bind(&array); |
1351 __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset)); | 1352 __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset)); |
1352 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); | 1353 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); |
1353 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 1354 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
1354 __ cmp(r1, ip); | 1355 __ cmp(r1, ip); |
1355 __ b(ne, &slow); | 1356 __ b(ne, &slow); |
1356 | 1357 |
1357 // Check the key against the length in the array, compute the | 1358 // Check the key against the length in the array, compute the |
1358 // address to store into and fall through to fast case. | 1359 // address to store into and fall through to fast case. |
1359 __ ldr(r1, MemOperand(sp)); // restore key | 1360 __ ldr(r1, MemOperand(sp)); // restore key |
1360 // r0 == value, r1 == key, r2 == elements, r3 == object. | 1361 // r0 == value, r1 == key, r2 == elements, r3 == object. |
1361 __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset)); | 1362 __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset)); |
1362 __ cmp(r1, Operand(ip)); | 1363 __ cmp(r1, Operand(ip)); |
1363 __ b(hs, &extra); | 1364 __ b(hs, &extra); |
1364 __ mov(r3, Operand(r2)); | 1365 __ mov(r3, Operand(r2)); |
1365 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 1366 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 1367 // The key is a smi. Assert we can shift left by 1 to use it as a |
| 1368 // byte offset. |
| 1369 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
1366 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); | 1370 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
1367 | 1371 |
1368 | 1372 |
1369 // Fast case: Do the store. | 1373 // Fast case: Do the store. |
1370 // r0 == value, r2 == address to store into, r3 == elements | 1374 // r0 == value, r2 == address to store into, r3 == elements |
1371 __ bind(&fast); | 1375 __ bind(&fast); |
1372 __ str(r0, MemOperand(r2)); | 1376 __ str(r0, MemOperand(r2)); |
1373 // Skip write barrier if the written value is a smi. | 1377 // Skip write barrier if the written value is a smi. |
1374 __ tst(r0, Operand(kSmiTagMask)); | 1378 __ tst(r0, Operand(kSmiTagMask)); |
1375 __ b(eq, &exit); | 1379 __ b(eq, &exit); |
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1834 __ bind(&miss); | 1838 __ bind(&miss); |
1835 | 1839 |
1836 GenerateMiss(masm); | 1840 GenerateMiss(masm); |
1837 } | 1841 } |
1838 | 1842 |
1839 | 1843 |
1840 #undef __ | 1844 #undef __ |
1841 | 1845 |
1842 | 1846 |
1843 } } // namespace v8::internal | 1847 } } // namespace v8::internal |
OLD | NEW |