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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 // r3 - used as temporary and to hold the capacity of the property | 58 // r3 - used as temporary and to hold the capacity of the property |
59 // dictionary. | 59 // dictionary. |
60 // | 60 // |
61 // r2 - holds the name of the property and is unchanged. | 61 // r2 - holds the name of the property and is unchanged. |
62 | 62 |
63 Label done; | 63 Label done; |
64 | 64 |
65 // Check for the absence of an interceptor. | 65 // Check for the absence of an interceptor. |
66 // Load the map into t0. | 66 // Load the map into t0. |
67 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); | 67 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); |
68 // Test the has_named_interceptor bit in the map. | 68 |
69 __ ldr(r3, FieldMemOperand(t0, Map::kInstanceAttributesOffset)); | 69 // Bail out if the receiver has a named interceptor. |
70 __ tst(r3, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8)))); | 70 __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset)); |
71 // Jump to miss if the interceptor bit is set. | 71 __ tst(r3, Operand(1 << Map::kHasNamedInterceptor)); |
72 __ b(ne, miss); | 72 __ b(nz, miss); |
73 | 73 |
74 // Bail out if we have a JS global proxy object. | 74 // Bail out if we have a JS global proxy object. |
75 __ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 75 __ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
76 __ cmp(r3, Operand(JS_GLOBAL_PROXY_TYPE)); | 76 __ cmp(r3, Operand(JS_GLOBAL_PROXY_TYPE)); |
77 __ b(eq, miss); | 77 __ b(eq, miss); |
78 | 78 |
79 // Possible work-around for http://crbug.com/16276. | 79 // Possible work-around for http://crbug.com/16276. |
80 // See also: http://codereview.chromium.org/155418. | 80 // See also: http://codereview.chromium.org/155418. |
81 __ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE)); | 81 __ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE)); |
82 __ b(eq, miss); | 82 __ b(eq, miss); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 __ bind(&done); // t1 == t0 + 4*index | 137 __ bind(&done); // t1 == t0 + 4*index |
138 __ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize)); | 138 __ ldr(r3, FieldMemOperand(t1, kElementsStartOffset + 2 * kPointerSize)); |
139 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 139 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
140 __ b(ne, miss); | 140 __ b(ne, miss); |
141 | 141 |
142 // Get the value at the masked, scaled index and return. | 142 // Get the value at the masked, scaled index and return. |
143 __ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize)); | 143 __ ldr(t1, FieldMemOperand(t1, kElementsStartOffset + 1 * kPointerSize)); |
144 } | 144 } |
145 | 145 |
146 | 146 |
| 147 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
| 148 Label* miss, |
| 149 Register elements, |
| 150 Register key, |
| 151 Register t0, |
| 152 Register t1, |
| 153 Register t2) { |
| 154 // Register use: |
| 155 // |
| 156 // elements - holds the slow-case elements of the receiver and is unchanged. |
| 157 // |
| 158 // key - holds the smi key on entry and is unchanged if a branch is |
| 159 // performed to the miss label. |
| 160 // |
| 161 // Scratch registers: |
| 162 // |
| 163 // t0 - holds the untagged key on entry and holds the hash once computed. |
| 164 // Holds the result on exit if the load succeeded. |
| 165 // |
| 166 // t1 - used to hold the capacity mask of the dictionary |
| 167 // |
| 168 // t2 - used for the index into the dictionary. |
| 169 Label done; |
| 170 |
| 171 // Compute the hash code from the untagged key. This must be kept in sync |
| 172 // with ComputeIntegerHash in utils.h. |
| 173 // |
| 174 // hash = ~hash + (hash << 15); |
| 175 __ mvn(t1, Operand(t0)); |
| 176 __ add(t0, t1, Operand(t0, LSL, 15)); |
| 177 // hash = hash ^ (hash >> 12); |
| 178 __ eor(t0, t0, Operand(t0, LSR, 12)); |
| 179 // hash = hash + (hash << 2); |
| 180 __ add(t0, t0, Operand(t0, LSL, 2)); |
| 181 // hash = hash ^ (hash >> 4); |
| 182 __ eor(t0, t0, Operand(t0, LSR, 4)); |
| 183 // hash = hash * 2057; |
| 184 __ mov(t1, Operand(2057)); |
| 185 __ mul(t0, t0, t1); |
| 186 // hash = hash ^ (hash >> 16); |
| 187 __ eor(t0, t0, Operand(t0, LSR, 16)); |
| 188 |
| 189 // Compute the capacity mask. |
| 190 __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset)); |
| 191 __ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int |
| 192 __ sub(t1, t1, Operand(1)); |
| 193 |
| 194 // Generate an unrolled loop that performs a few probes before giving up. |
| 195 static const int kProbes = 4; |
| 196 for (int i = 0; i < kProbes; i++) { |
| 197 // Use t2 for index calculations and keep the hash intact in t0. |
| 198 __ mov(t2, t0); |
| 199 // Compute the masked index: (hash + i + i * i) & mask. |
| 200 if (i > 0) { |
| 201 __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i))); |
| 202 } |
| 203 __ and_(t2, t2, Operand(t1)); |
| 204 |
| 205 // Scale the index by multiplying by the element size. |
| 206 ASSERT(NumberDictionary::kEntrySize == 3); |
| 207 __ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3 |
| 208 |
| 209 // Check if the key is identical to the name. |
| 210 __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2)); |
| 211 __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset)); |
| 212 __ cmp(key, Operand(ip)); |
| 213 if (i != kProbes - 1) { |
| 214 __ b(eq, &done); |
| 215 } else { |
| 216 __ b(ne, miss); |
| 217 } |
| 218 } |
| 219 |
| 220 __ bind(&done); |
| 221 // Check that the value is a normal property. |
| 222 // t2: elements + (index * kPointerSize) |
| 223 const int kDetailsOffset = |
| 224 NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
| 225 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset)); |
| 226 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); |
| 227 __ b(ne, miss); |
| 228 |
| 229 // Get the value at the masked, scaled index and return. |
| 230 const int kValueOffset = |
| 231 NumberDictionary::kElementsStartOffset + kPointerSize; |
| 232 __ ldr(t0, FieldMemOperand(t2, kValueOffset)); |
| 233 } |
| 234 |
| 235 |
147 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { | 236 void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
148 // ----------- S t a t e ------------- | 237 // ----------- S t a t e ------------- |
149 // -- r2 : name | 238 // -- r2 : name |
150 // -- lr : return address | 239 // -- lr : return address |
151 // -- [sp] : receiver | 240 // -- [sp] : receiver |
152 // ----------------------------------- | 241 // ----------------------------------- |
153 Label miss; | 242 Label miss; |
154 | 243 |
155 __ ldr(r0, MemOperand(sp, 0)); | 244 __ ldr(r0, MemOperand(sp, 0)); |
156 | 245 |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
523 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); | 612 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); |
524 } | 613 } |
525 | 614 |
526 | 615 |
527 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 616 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
528 // ---------- S t a t e -------------- | 617 // ---------- S t a t e -------------- |
529 // -- lr : return address | 618 // -- lr : return address |
530 // -- sp[0] : key | 619 // -- sp[0] : key |
531 // -- sp[4] : receiver | 620 // -- sp[4] : receiver |
532 // ----------------------------------- | 621 // ----------------------------------- |
533 Label slow, fast, check_pixel_array; | 622 Label slow, fast, check_pixel_array, check_number_dictionary; |
534 | 623 |
535 // Get the key and receiver object from the stack. | 624 // Get the key and receiver object from the stack. |
536 __ ldm(ia, sp, r0.bit() | r1.bit()); | 625 __ ldm(ia, sp, r0.bit() | r1.bit()); |
537 | 626 |
538 // Check that the object isn't a smi. | 627 // Check that the object isn't a smi. |
539 __ BranchOnSmi(r1, &slow); | 628 __ BranchOnSmi(r1, &slow); |
540 // Get the map of the receiver. | 629 // Get the map of the receiver. |
541 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | 630 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
542 // Check bit field. | 631 // Check bit field. |
543 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); | 632 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); |
544 __ tst(r3, Operand(kSlowCaseBitFieldMask)); | 633 __ tst(r3, Operand(kSlowCaseBitFieldMask)); |
545 __ b(ne, &slow); | 634 __ b(ne, &slow); |
546 // Check that the object is some kind of JS object EXCEPT JS Value type. | 635 // Check that the object is some kind of JS object EXCEPT JS Value type. |
547 // In the case that the object is a value-wrapper object, | 636 // In the case that the object is a value-wrapper object, |
548 // we enter the runtime system to make sure that indexing into string | 637 // we enter the runtime system to make sure that indexing into string |
549 // objects work as intended. | 638 // objects work as intended. |
550 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 639 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
551 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 640 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
552 __ cmp(r2, Operand(JS_OBJECT_TYPE)); | 641 __ cmp(r2, Operand(JS_OBJECT_TYPE)); |
553 __ b(lt, &slow); | 642 __ b(lt, &slow); |
554 | 643 |
555 // Check that the key is a smi. | 644 // Check that the key is a smi. |
556 __ BranchOnNotSmi(r0, &slow); | 645 __ BranchOnNotSmi(r0, &slow); |
| 646 // Save key in r2 in case we want it for the number dictionary case. |
| 647 __ mov(r2, r0); |
557 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); | 648 __ mov(r0, Operand(r0, ASR, kSmiTagSize)); |
558 | 649 |
559 // Get the elements array of the object. | 650 // Get the elements array of the object. |
560 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); | 651 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
561 // Check that the object is in fast mode (not dictionary). | 652 // Check that the object is in fast mode (not dictionary). |
562 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); | 653 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
563 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 654 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
564 __ cmp(r3, ip); | 655 __ cmp(r3, ip); |
565 __ b(ne, &slow); | 656 __ b(ne, &check_pixel_array); |
566 // Check that the key (index) is within bounds. | 657 // Check that the key (index) is within bounds. |
567 __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); | 658 __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); |
568 __ cmp(r0, Operand(r3)); | 659 __ cmp(r0, Operand(r3)); |
569 __ b(lo, &fast); | 660 __ b(ge, &slow); |
| 661 // Fast case: Do the load. |
| 662 __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 663 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); |
| 664 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
| 665 __ cmp(r0, ip); |
| 666 // In case the loaded value is the_hole we have to consult GetProperty |
| 667 // to ensure the prototype chain is searched. |
| 668 __ b(eq, &slow); |
| 669 __ Ret(); |
570 | 670 |
571 // Check whether the elements is a pixel array. | 671 // Check whether the elements is a pixel array. |
572 __ bind(&check_pixel_array); | 672 __ bind(&check_pixel_array); |
573 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); | 673 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); |
574 __ cmp(r3, ip); | 674 __ cmp(r3, ip); |
575 __ b(ne, &slow); | 675 __ b(ne, &check_number_dictionary); |
576 __ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset)); | 676 __ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset)); |
577 __ cmp(r0, ip); | 677 __ cmp(r0, ip); |
578 __ b(hs, &slow); | 678 __ b(hs, &slow); |
579 __ ldr(ip, FieldMemOperand(r1, PixelArray::kExternalPointerOffset)); | 679 __ ldr(ip, FieldMemOperand(r1, PixelArray::kExternalPointerOffset)); |
580 __ ldrb(r0, MemOperand(ip, r0)); | 680 __ ldrb(r0, MemOperand(ip, r0)); |
581 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Tag result as smi. | 681 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Tag result as smi. |
582 __ Ret(); | 682 __ Ret(); |
583 | 683 |
| 684 __ bind(&check_number_dictionary); |
| 685 // Check whether the elements is a number dictionary. |
| 686 // r0: untagged index |
| 687 // r1: elements |
| 688 // r2: key |
| 689 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 690 __ cmp(r3, ip); |
| 691 __ b(ne, &slow); |
| 692 GenerateNumberDictionaryLoad(masm, &slow, r1, r2, r0, r3, r4); |
| 693 __ Ret(); |
| 694 |
584 // Slow case: Push extra copies of the arguments (2). | 695 // Slow case: Push extra copies of the arguments (2). |
585 __ bind(&slow); | 696 __ bind(&slow); |
586 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1); | 697 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1); |
587 GenerateRuntimeGetProperty(masm); | 698 GenerateRuntimeGetProperty(masm); |
588 | |
589 // Fast case: Do the load. | |
590 __ bind(&fast); | |
591 __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
592 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); | |
593 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | |
594 __ cmp(r0, ip); | |
595 // In case the loaded value is the_hole we have to consult GetProperty | |
596 // to ensure the prototype chain is searched. | |
597 __ b(eq, &slow); | |
598 | |
599 __ Ret(); | |
600 } | 699 } |
601 | 700 |
602 | 701 |
603 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 702 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
604 // ---------- S t a t e -------------- | 703 // ---------- S t a t e -------------- |
605 // -- lr : return address | 704 // -- lr : return address |
606 // -- sp[0] : key | 705 // -- sp[0] : key |
607 // -- sp[4] : receiver | 706 // -- sp[4] : receiver |
608 // ----------------------------------- | 707 // ----------------------------------- |
609 | 708 |
(...skipping 953 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1563 __ bind(&miss); | 1662 __ bind(&miss); |
1564 | 1663 |
1565 GenerateMiss(masm); | 1664 GenerateMiss(masm); |
1566 } | 1665 } |
1567 | 1666 |
1568 | 1667 |
1569 #undef __ | 1668 #undef __ |
1570 | 1669 |
1571 | 1670 |
1572 } } // namespace v8::internal | 1671 } } // namespace v8::internal |
OLD | NEW |