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 30 matching lines...) Expand all Loading... |
41 namespace internal { | 41 namespace internal { |
42 | 42 |
43 | 43 |
44 // ---------------------------------------------------------------------------- | 44 // ---------------------------------------------------------------------------- |
45 // Static IC stub generators. | 45 // Static IC stub generators. |
46 // | 46 // |
47 | 47 |
48 #define __ ACCESS_MASM(masm) | 48 #define __ ACCESS_MASM(masm) |
49 | 49 |
50 // Helper function used from LoadIC/CallIC GenerateNormal. | 50 // Helper function used from LoadIC/CallIC GenerateNormal. |
| 51 // receiver: Receiver. It is not clobbered if a jump to the miss label is |
| 52 // done |
| 53 // name: Property name. It is not clobbered if a jump to the miss label is |
| 54 // done |
| 55 // result: Register for the result. It is only updated if a jump to the miss |
| 56 // label is not done. Can be the same as receiver or name clobbering |
| 57 // one of these in the case of not jumping to the miss label. |
| 58 // The three scratch registers need to be different from the receiver, name and |
| 59 // result. |
51 static void GenerateDictionaryLoad(MacroAssembler* masm, | 60 static void GenerateDictionaryLoad(MacroAssembler* masm, |
52 Label* miss, | 61 Label* miss, |
53 Register t0, | 62 Register receiver, |
54 Register t1) { | 63 Register name, |
55 // Register use: | 64 Register result, |
56 // | 65 Register scratch1, |
57 // t0 - used to hold the property dictionary. | 66 Register scratch2, |
58 // | 67 Register scratch3, |
59 // t1 - initially the receiver. | 68 DictionaryCheck check_dictionary) { |
60 // - holds the result on exit. | 69 // Main use of the scratch registers. |
61 // | 70 // scratch1: Used to hold the property dictionary. |
62 // r3 - used as temporary and to hold the capacity of the property | 71 // scratch2: Used as temporary and to hold the capacity of the property |
63 // dictionary. | 72 // dictionary. |
64 // | 73 // scratch3: Used as temporary. |
65 // r2 - initially holds the name of the property and is unchanged. | |
66 // r4 - used to hold the index into the property dictionary. | |
67 | 74 |
68 Label done; | 75 Label done; |
69 | 76 |
70 // Check for the absence of an interceptor. | 77 // Check for the absence of an interceptor. |
71 // Load the map into t0. | 78 // Load the map into scratch1. |
72 __ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); | 79 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kMapOffset)); |
73 | 80 |
74 // Bail out if the receiver has a named interceptor. | 81 // Bail out if the receiver has a named interceptor. |
75 __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset)); | 82 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset)); |
76 __ tst(r3, Operand(1 << Map::kHasNamedInterceptor)); | 83 __ tst(scratch2, Operand(1 << Map::kHasNamedInterceptor)); |
77 __ b(nz, miss); | 84 __ b(nz, miss); |
78 | 85 |
79 // Bail out if we have a JS global proxy object. | 86 // Bail out if we have a JS global proxy object. |
80 __ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 87 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
81 __ cmp(r3, Operand(JS_GLOBAL_PROXY_TYPE)); | 88 __ cmp(scratch2, Operand(JS_GLOBAL_PROXY_TYPE)); |
82 __ b(eq, miss); | 89 __ b(eq, miss); |
83 | 90 |
84 // Possible work-around for http://crbug.com/16276. | 91 // Possible work-around for http://crbug.com/16276. |
85 // See also: http://codereview.chromium.org/155418. | 92 // See also: http://codereview.chromium.org/155418. |
86 __ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE)); | 93 __ cmp(scratch2, Operand(JS_GLOBAL_OBJECT_TYPE)); |
87 __ b(eq, miss); | 94 __ b(eq, miss); |
88 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE)); | 95 __ cmp(scratch2, Operand(JS_BUILTINS_OBJECT_TYPE)); |
89 __ b(eq, miss); | 96 __ b(eq, miss); |
90 | 97 |
| 98 // Load the properties array. |
| 99 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
| 100 |
91 // Check that the properties array is a dictionary. | 101 // Check that the properties array is a dictionary. |
92 __ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset)); | 102 if (check_dictionary == CHECK_DICTIONARY) { |
93 __ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset)); | 103 __ ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset)); |
94 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | 104 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
95 __ cmp(r3, ip); | 105 __ cmp(scratch2, ip); |
96 __ b(ne, miss); | 106 __ b(ne, miss); |
| 107 } |
97 | 108 |
98 // Compute the capacity mask. | 109 // Compute the capacity mask. |
99 const int kCapacityOffset = StringDictionary::kHeaderSize + | 110 const int kCapacityOffset = StringDictionary::kHeaderSize + |
100 StringDictionary::kCapacityIndex * kPointerSize; | 111 StringDictionary::kCapacityIndex * kPointerSize; |
101 __ ldr(r3, FieldMemOperand(t0, kCapacityOffset)); | 112 __ ldr(scratch2, FieldMemOperand(scratch1, kCapacityOffset)); |
102 __ mov(r3, Operand(r3, ASR, kSmiTagSize)); // convert smi to int | 113 __ mov(scratch2, Operand(scratch2, ASR, kSmiTagSize)); // convert smi to int |
103 __ sub(r3, r3, Operand(1)); | 114 __ sub(scratch2, scratch2, Operand(1)); |
104 | 115 |
105 const int kElementsStartOffset = StringDictionary::kHeaderSize + | 116 const int kElementsStartOffset = StringDictionary::kHeaderSize + |
106 StringDictionary::kElementsStartIndex * kPointerSize; | 117 StringDictionary::kElementsStartIndex * kPointerSize; |
107 | 118 |
108 // Generate an unrolled loop that performs a few probes before | 119 // Generate an unrolled loop that performs a few probes before |
109 // giving up. Measurements done on Gmail indicate that 2 probes | 120 // giving up. Measurements done on Gmail indicate that 2 probes |
110 // cover ~93% of loads from dictionaries. | 121 // cover ~93% of loads from dictionaries. |
111 static const int kProbes = 4; | 122 static const int kProbes = 4; |
112 for (int i = 0; i < kProbes; i++) { | 123 for (int i = 0; i < kProbes; i++) { |
113 // Compute the masked index: (hash + i + i * i) & mask. | 124 // Compute the masked index: (hash + i + i * i) & mask. |
114 __ ldr(r4, FieldMemOperand(r2, String::kHashFieldOffset)); | 125 __ ldr(scratch3, FieldMemOperand(name, String::kHashFieldOffset)); |
115 if (i > 0) { | 126 if (i > 0) { |
116 // Add the probe offset (i + i * i) left shifted to avoid right shifting | 127 // Add the probe offset (i + i * i) left shifted to avoid right shifting |
117 // the hash in a separate instruction. The value hash + i + i * i is right | 128 // the hash in a separate instruction. The value hash + i + i * i is right |
118 // shifted in the following and instruction. | 129 // shifted in the following and instruction. |
119 ASSERT(StringDictionary::GetProbeOffset(i) < | 130 ASSERT(StringDictionary::GetProbeOffset(i) < |
120 1 << (32 - String::kHashFieldOffset)); | 131 1 << (32 - String::kHashFieldOffset)); |
121 __ add(r4, r4, Operand( | 132 __ add(scratch3, scratch3, Operand( |
122 StringDictionary::GetProbeOffset(i) << String::kHashShift)); | 133 StringDictionary::GetProbeOffset(i) << String::kHashShift)); |
123 } | 134 } |
124 __ and_(r4, r3, Operand(r4, LSR, String::kHashShift)); | 135 __ and_(scratch3, scratch2, Operand(scratch3, LSR, String::kHashShift)); |
125 | 136 |
126 // Scale the index by multiplying by the element size. | 137 // Scale the index by multiplying by the element size. |
127 ASSERT(StringDictionary::kEntrySize == 3); | 138 ASSERT(StringDictionary::kEntrySize == 3); |
128 __ add(r4, r4, Operand(r4, LSL, 1)); // r4 = r4 * 3 | 139 // scratch3 = scratch3 * 3. |
| 140 __ add(scratch3, scratch3, Operand(scratch3, LSL, 1)); |
129 | 141 |
130 // Check if the key is identical to the name. | 142 // Check if the key is identical to the name. |
131 __ add(r4, t0, Operand(r4, LSL, 2)); | 143 __ add(scratch3, scratch1, Operand(scratch3, LSL, 2)); |
132 __ ldr(ip, FieldMemOperand(r4, kElementsStartOffset)); | 144 __ ldr(ip, FieldMemOperand(scratch3, kElementsStartOffset)); |
133 __ cmp(r2, Operand(ip)); | 145 __ cmp(name, Operand(ip)); |
134 if (i != kProbes - 1) { | 146 if (i != kProbes - 1) { |
135 __ b(eq, &done); | 147 __ b(eq, &done); |
136 } else { | 148 } else { |
137 __ b(ne, miss); | 149 __ b(ne, miss); |
138 } | 150 } |
139 } | 151 } |
140 | 152 |
141 // Check that the value is a normal property. | 153 // Check that the value is a normal property. |
142 __ bind(&done); // r4 == t0 + 4*index | 154 __ bind(&done); // scratch3 == scratch1 + 4 * index |
143 __ ldr(r3, FieldMemOperand(r4, kElementsStartOffset + 2 * kPointerSize)); | 155 __ ldr(scratch2, |
144 __ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); | 156 FieldMemOperand(scratch3, kElementsStartOffset + 2 * kPointerSize)); |
| 157 __ tst(scratch2, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize)); |
145 __ b(ne, miss); | 158 __ b(ne, miss); |
146 | 159 |
147 // Get the value at the masked, scaled index and return. | 160 // Get the value at the masked, scaled index and return. |
148 __ ldr(t1, FieldMemOperand(r4, kElementsStartOffset + 1 * kPointerSize)); | 161 __ ldr(result, |
| 162 FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize)); |
149 } | 163 } |
150 | 164 |
151 | 165 |
152 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, | 166 static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
153 Label* miss, | 167 Label* miss, |
154 Register elements, | 168 Register elements, |
155 Register key, | 169 Register key, |
156 Register t0, | 170 Register t0, |
157 Register t1, | 171 Register t1, |
158 Register t2) { | 172 Register t2) { |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 GenerateMiss(masm, argc); | 360 GenerateMiss(masm, argc); |
347 } | 361 } |
348 | 362 |
349 | 363 |
350 static void GenerateNormalHelper(MacroAssembler* masm, | 364 static void GenerateNormalHelper(MacroAssembler* masm, |
351 int argc, | 365 int argc, |
352 bool is_global_object, | 366 bool is_global_object, |
353 Label* miss, | 367 Label* miss, |
354 Register scratch) { | 368 Register scratch) { |
355 // Search dictionary - put result in register r1. | 369 // Search dictionary - put result in register r1. |
356 GenerateDictionaryLoad(masm, miss, r0, r1); | 370 GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY); |
357 | 371 |
358 // Check that the value isn't a smi. | 372 // Check that the value isn't a smi. |
359 __ tst(r1, Operand(kSmiTagMask)); | 373 __ tst(r1, Operand(kSmiTagMask)); |
360 __ b(eq, miss); | 374 __ b(eq, miss); |
361 | 375 |
362 // Check that the value is a JSFunction. | 376 // Check that the value is a JSFunction. |
363 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE); | 377 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE); |
364 __ b(ne, miss); | 378 __ b(ne, miss); |
365 | 379 |
366 // Patch the receiver with the global proxy if necessary. | 380 // Patch the receiver with the global proxy if necessary. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 // Check for access to global object (unlikely). | 540 // Check for access to global object (unlikely). |
527 __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE)); | 541 __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE)); |
528 __ b(eq, &global); | 542 __ b(eq, &global); |
529 | 543 |
530 // Check for non-global object that requires access check. | 544 // Check for non-global object that requires access check. |
531 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); | 545 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset)); |
532 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); | 546 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded)); |
533 __ b(ne, &miss); | 547 __ b(ne, &miss); |
534 | 548 |
535 __ bind(&probe); | 549 __ bind(&probe); |
536 GenerateDictionaryLoad(masm, &miss, r1, r0); | 550 GenerateDictionaryLoad(masm, &miss, r0, r2, r0, r1, r3, r4, CHECK_DICTIONARY); |
537 __ Ret(); | 551 __ Ret(); |
538 | 552 |
539 // Global object access: Check access rights. | 553 // Global object access: Check access rights. |
540 __ bind(&global); | 554 __ bind(&global); |
541 __ CheckAccessGlobalProxy(r0, r1, &miss); | 555 __ CheckAccessGlobalProxy(r0, r1, &miss); |
542 __ b(&probe); | 556 __ b(&probe); |
543 | 557 |
544 // Cache miss: Jump to runtime. | 558 // Cache miss: Jump to runtime. |
545 __ bind(&miss); | 559 __ bind(&miss); |
546 GenerateMiss(masm); | 560 GenerateMiss(masm); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 | 721 |
708 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 722 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
709 // ---------- S t a t e -------------- | 723 // ---------- S t a t e -------------- |
710 // -- lr : return address | 724 // -- lr : return address |
711 // -- r0 : key | 725 // -- r0 : key |
712 // -- r1 : receiver | 726 // -- r1 : receiver |
713 // ----------------------------------- | 727 // ----------------------------------- |
714 | 728 |
715 __ Push(r1, r0); | 729 __ Push(r1, r0); |
716 | 730 |
717 __ TailCallRuntime(Runtime::kGetProperty, 2, 1); | 731 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
718 } | 732 } |
719 | 733 |
720 | 734 |
721 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { | 735 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
722 // ---------- S t a t e -------------- | 736 // ---------- S t a t e -------------- |
723 // -- lr : return address | 737 // -- lr : return address |
724 // -- r0 : key | 738 // -- r0 : key |
725 // -- r1 : receiver | 739 // -- r1 : receiver |
726 // ----------------------------------- | 740 // ----------------------------------- |
727 Label slow, fast, check_pixel_array, check_number_dictionary; | 741 Label slow, check_string, index_smi, index_string; |
| 742 Label check_pixel_array, probe_dictionary, check_number_dictionary; |
728 | 743 |
729 Register key = r0; | 744 Register key = r0; |
730 Register receiver = r1; | 745 Register receiver = r1; |
731 | 746 |
732 // Check that the object isn't a smi. | 747 // Check that the object isn't a smi. |
733 __ BranchOnSmi(receiver, &slow); | 748 __ BranchOnSmi(receiver, &slow); |
734 // Get the map of the receiver. | 749 // Get the map of the receiver. |
735 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 750 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
736 // Check bit field. | 751 // Check bit field. |
737 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); | 752 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset)); |
738 __ tst(r3, Operand(kSlowCaseBitFieldMask)); | 753 __ tst(r3, Operand(kSlowCaseBitFieldMask)); |
739 __ b(ne, &slow); | 754 __ b(ne, &slow); |
740 // Check that the object is some kind of JS object EXCEPT JS Value type. | 755 // Check that the object is some kind of JS object EXCEPT JS Value type. |
741 // In the case that the object is a value-wrapper object, | 756 // In the case that the object is a value-wrapper object, |
742 // we enter the runtime system to make sure that indexing into string | 757 // we enter the runtime system to make sure that indexing into string |
743 // objects work as intended. | 758 // objects work as intended. |
744 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); | 759 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
745 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | 760 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
746 __ cmp(r2, Operand(JS_OBJECT_TYPE)); | 761 __ cmp(r2, Operand(JS_OBJECT_TYPE)); |
747 __ b(lt, &slow); | 762 __ b(lt, &slow); |
748 | 763 |
749 // Check that the key is a smi. | 764 // Check that the key is a smi. |
750 __ BranchOnNotSmi(key, &slow); | 765 __ BranchOnNotSmi(key, &check_string); |
751 // Get the elements array of the object. | 766 __ bind(&index_smi); |
| 767 // Now the key is known to be a smi. This place is also jumped to from below |
| 768 // where a numeric string is converted to a smi. |
752 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | 769 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); |
753 // Check that the object is in fast mode (not dictionary). | 770 // Check that the object is in fast mode (not dictionary). |
754 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); | 771 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset)); |
755 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); | 772 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
756 __ cmp(r3, ip); | 773 __ cmp(r3, ip); |
757 __ b(ne, &check_pixel_array); | 774 __ b(ne, &check_pixel_array); |
758 // Check that the key (index) is within bounds. | 775 // Check that the key (index) is within bounds. |
759 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); | 776 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset)); |
760 __ cmp(key, Operand(r3)); | 777 __ cmp(key, Operand(r3)); |
761 __ b(hs, &slow); | 778 __ b(hs, &slow); |
762 // Fast case: Do the load. | 779 // Fast case: Do the load. |
763 __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 780 __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
764 // The key is a smi. | 781 // The key is a smi. |
765 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); | 782 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2); |
766 __ ldr(r2, MemOperand(r3, key, LSL, kPointerSizeLog2 - kSmiTagSize)); | 783 __ ldr(r2, MemOperand(r3, key, LSL, kPointerSizeLog2 - kSmiTagSize)); |
767 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 784 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
768 __ cmp(r2, ip); | 785 __ cmp(r2, ip); |
769 // In case the loaded value is the_hole we have to consult GetProperty | 786 // In case the loaded value is the_hole we have to consult GetProperty |
770 // to ensure the prototype chain is searched. | 787 // to ensure the prototype chain is searched. |
771 __ b(eq, &slow); | 788 __ b(eq, &slow); |
772 __ mov(r0, r2); | 789 __ mov(r0, r2); |
| 790 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3); |
773 __ Ret(); | 791 __ Ret(); |
774 | 792 |
775 // Check whether the elements is a pixel array. | 793 // Check whether the elements is a pixel array. |
776 // r0: key | 794 // r0: key |
777 // r3: elements map | 795 // r3: elements map |
778 // r4: elements | 796 // r4: elements |
779 __ bind(&check_pixel_array); | 797 __ bind(&check_pixel_array); |
780 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); | 798 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); |
781 __ cmp(r3, ip); | 799 __ cmp(r3, ip); |
782 __ b(ne, &check_number_dictionary); | 800 __ b(ne, &check_number_dictionary); |
(...skipping 15 matching lines...) Expand all Loading... |
798 __ cmp(r3, ip); | 816 __ cmp(r3, ip); |
799 __ b(ne, &slow); | 817 __ b(ne, &slow); |
800 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); | 818 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); |
801 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5); | 819 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5); |
802 __ Ret(); | 820 __ Ret(); |
803 | 821 |
804 // Slow case, key and receiver still in r0 and r1. | 822 // Slow case, key and receiver still in r0 and r1. |
805 __ bind(&slow); | 823 __ bind(&slow); |
806 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); | 824 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3); |
807 GenerateRuntimeGetProperty(masm); | 825 GenerateRuntimeGetProperty(masm); |
| 826 |
| 827 __ bind(&check_string); |
| 828 // The key is not a smi. |
| 829 // Is it a string? |
| 830 // r0: key |
| 831 // r1: receiver |
| 832 __ CompareObjectType(r0, r2, r3, FIRST_NONSTRING_TYPE); |
| 833 __ b(ge, &slow); |
| 834 |
| 835 // Is the string an array index, with cached numeric value? |
| 836 __ ldr(r3, FieldMemOperand(r0, String::kHashFieldOffset)); |
| 837 __ tst(r3, Operand(String::kIsArrayIndexMask)); |
| 838 __ b(ne, &index_string); |
| 839 |
| 840 // Is the string a symbol? |
| 841 // r2: key map |
| 842 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| 843 ASSERT(kSymbolTag != 0); |
| 844 __ tst(r3, Operand(kIsSymbolMask)); |
| 845 __ b(eq, &slow); |
| 846 |
| 847 // If the receiver is a fast-case object, check the keyed lookup |
| 848 // cache. Otherwise probe the dictionary. |
| 849 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset)); |
| 850 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset)); |
| 851 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
| 852 __ cmp(r3, ip); |
| 853 __ b(eq, &probe_dictionary); |
| 854 |
| 855 // Load the map of the receiver, compute the keyed lookup cache hash |
| 856 // based on 32 bits of the map pointer and the string hash. |
| 857 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 858 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift)); |
| 859 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset)); |
| 860 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift)); |
| 861 __ and_(r3, r3, Operand(KeyedLookupCache::kCapacityMask)); |
| 862 |
| 863 // Load the key (consisting of map and symbol) from the cache and |
| 864 // check for match. |
| 865 ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys(); |
| 866 __ mov(r4, Operand(cache_keys)); |
| 867 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1)); |
| 868 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol. |
| 869 __ cmp(r2, r5); |
| 870 __ b(ne, &slow); |
| 871 __ ldr(r5, MemOperand(r4)); |
| 872 __ cmp(r0, r5); |
| 873 __ b(ne, &slow); |
| 874 |
| 875 // Get field offset and check that it is an in-object property. |
| 876 // r0 : key |
| 877 // r1 : receiver |
| 878 // r2 : receiver's map |
| 879 // r3 : lookup cache index |
| 880 ExternalReference cache_field_offsets |
| 881 = ExternalReference::keyed_lookup_cache_field_offsets(); |
| 882 __ mov(r4, Operand(cache_field_offsets)); |
| 883 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2)); |
| 884 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset)); |
| 885 __ cmp(r5, r6); |
| 886 __ b(ge, &slow); |
| 887 |
| 888 // Load in-object property. |
| 889 __ sub(r5, r5, r6); // Index from end of object. |
| 890 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset)); |
| 891 __ add(r6, r6, r5); // Index from start of object. |
| 892 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag. |
| 893 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2)); |
| 894 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3); |
| 895 __ Ret(); |
| 896 |
| 897 // Do a quick inline probe of the receiver's dictionary, if it |
| 898 // exists. |
| 899 __ bind(&probe_dictionary); |
| 900 // Load the property to r0. |
| 901 GenerateDictionaryLoad( |
| 902 masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE); |
| 903 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3); |
| 904 __ Ret(); |
| 905 |
| 906 __ b(&slow); |
| 907 // If the hash field contains an array index pick it out. The assert checks |
| 908 // that the constants for the maximum number of digits for an array index |
| 909 // cached in the hash field and the number of bits reserved for it does not |
| 910 // conflict. |
| 911 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) < |
| 912 (1 << String::kArrayIndexValueBits)); |
| 913 __ bind(&index_string); |
| 914 // r0: key (string) |
| 915 // r1: receiver |
| 916 // r3: hash field |
| 917 // We want the smi-tagged index in r0. kArrayIndexValueMask has zeros in |
| 918 // the low kHashShift bits. |
| 919 ASSERT(String::kHashShift >= kSmiTagSize); |
| 920 __ and_(r3, r3, Operand(String::kArrayIndexValueMask)); |
| 921 // Here we actually clobber the key (r0) which will be used if calling into |
| 922 // runtime later. However as the new key is the numeric value of a string key |
| 923 // there is no difference in using either key. |
| 924 __ mov(r0, Operand(r3, ASR, String::kHashShift - kSmiTagSize)); |
| 925 // Now jump to the place where smi keys are handled. |
| 926 __ jmp(&index_smi); |
808 } | 927 } |
809 | 928 |
810 | 929 |
811 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { | 930 void KeyedLoadIC::GenerateString(MacroAssembler* masm) { |
812 // ---------- S t a t e -------------- | 931 // ---------- S t a t e -------------- |
813 // -- lr : return address | 932 // -- lr : return address |
814 // -- r0 : key (index) | 933 // -- r0 : key (index) |
815 // -- r1 : receiver | 934 // -- r1 : receiver |
816 // ----------------------------------- | 935 // ----------------------------------- |
817 Label miss; | 936 Label miss; |
(...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1806 GenerateMiss(masm); | 1925 GenerateMiss(masm); |
1807 } | 1926 } |
1808 | 1927 |
1809 | 1928 |
1810 #undef __ | 1929 #undef __ |
1811 | 1930 |
1812 | 1931 |
1813 } } // namespace v8::internal | 1932 } } // namespace v8::internal |
1814 | 1933 |
1815 #endif // V8_TARGET_ARCH_ARM | 1934 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |