OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_X87 | 5 #if V8_TARGET_ARCH_X87 |
6 | 6 |
7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
8 #include "src/ic/ic.h" | 8 #include "src/ic/ic.h" |
9 #include "src/ic/ic-compiler.h" | 9 #include "src/ic/ic-compiler.h" |
10 #include "src/ic/stub-cache.h" | 10 #include "src/ic/stub-cache.h" |
11 | 11 |
12 namespace v8 { | 12 namespace v8 { |
13 namespace internal { | 13 namespace internal { |
14 | 14 |
15 // ---------------------------------------------------------------------------- | 15 // ---------------------------------------------------------------------------- |
16 // Static IC stub generators. | 16 // Static IC stub generators. |
17 // | 17 // |
18 | 18 |
19 #define __ ACCESS_MASM(masm) | 19 #define __ ACCESS_MASM(masm) |
20 | 20 |
21 // Helper function used to load a property from a dictionary backing | |
22 // storage. This function may fail to load a property even though it is | |
23 // in the dictionary, so code at miss_label must always call a backup | |
24 // property load that is complete. This function is safe to call if | |
25 // name is not internalized, and will jump to the miss_label in that | |
26 // case. The generated code assumes that the receiver has slow | |
27 // properties, is not a global object and does not have interceptors. | |
28 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss_label, | |
29 Register elements, Register name, | |
30 Register r0, Register r1, Register result) { | |
31 // Register use: | |
32 // | |
33 // elements - holds the property dictionary on entry and is unchanged. | |
34 // | |
35 // name - holds the name of the property on entry and is unchanged. | |
36 // | |
37 // Scratch registers: | |
38 // | |
39 // r0 - used for the index into the property dictionary | |
40 // | |
41 // r1 - used to hold the capacity of the property dictionary. | |
42 // | |
43 // result - holds the result on exit. | |
44 | |
45 Label done; | |
46 | |
47 // Probe the dictionary. | |
48 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, | |
49 elements, name, r0, r1); | |
50 | |
51 // If probing finds an entry in the dictionary, r0 contains the | |
52 // index into the dictionary. Check that the value is a normal | |
53 // property. | |
54 __ bind(&done); | |
55 const int kElementsStartOffset = | |
56 NameDictionary::kHeaderSize + | |
57 NameDictionary::kElementsStartIndex * kPointerSize; | |
58 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
59 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | |
60 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize)); | |
61 __ j(not_zero, miss_label); | |
62 | |
63 // Get the value at the masked, scaled index. | |
64 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
65 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | |
66 } | |
67 | |
68 | |
69 // Helper function used to store a property to a dictionary backing | |
70 // storage. This function may fail to store a property eventhough it | |
71 // is in the dictionary, so code at miss_label must always call a | |
72 // backup property store that is complete. This function is safe to | |
73 // call if name is not internalized, and will jump to the miss_label in | |
74 // that case. The generated code assumes that the receiver has slow | |
75 // properties, is not a global object and does not have interceptors. | |
76 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label, | |
77 Register elements, Register name, | |
78 Register value, Register r0, Register r1) { | |
79 // Register use: | |
80 // | |
81 // elements - holds the property dictionary on entry and is clobbered. | |
82 // | |
83 // name - holds the name of the property on entry and is unchanged. | |
84 // | |
85 // value - holds the value to store and is unchanged. | |
86 // | |
87 // r0 - used for index into the property dictionary and is clobbered. | |
88 // | |
89 // r1 - used to hold the capacity of the property dictionary and is clobbered. | |
90 Label done; | |
91 | |
92 | |
93 // Probe the dictionary. | |
94 NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss_label, &done, | |
95 elements, name, r0, r1); | |
96 | |
97 // If probing finds an entry in the dictionary, r0 contains the | |
98 // index into the dictionary. Check that the value is a normal | |
99 // property that is not read only. | |
100 __ bind(&done); | |
101 const int kElementsStartOffset = | |
102 NameDictionary::kHeaderSize + | |
103 NameDictionary::kElementsStartIndex * kPointerSize; | |
104 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize; | |
105 const int kTypeAndReadOnlyMask = | |
106 (PropertyDetails::TypeField::kMask | | |
107 PropertyDetails::AttributesField::encode(READ_ONLY)) | |
108 << kSmiTagSize; | |
109 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag), | |
110 Immediate(kTypeAndReadOnlyMask)); | |
111 __ j(not_zero, miss_label); | |
112 | |
113 // Store the value at the masked, scaled index. | |
114 const int kValueOffset = kElementsStartOffset + kPointerSize; | |
115 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag)); | |
116 __ mov(Operand(r0, 0), value); | |
117 | |
118 // Update write barrier. Make sure not to clobber the value. | |
119 __ mov(r1, value); | |
120 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs); | |
121 } | |
122 | |
123 void LoadIC::GenerateNormal(MacroAssembler* masm) { | |
124 Register dictionary = eax; | |
125 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); | |
126 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); | |
127 | |
128 Label slow; | |
129 | |
130 __ mov(dictionary, FieldOperand(LoadDescriptor::ReceiverRegister(), | |
131 JSObject::kPropertiesOffset)); | |
132 GenerateDictionaryLoad(masm, &slow, dictionary, | |
133 LoadDescriptor::NameRegister(), edi, ebx, eax); | |
134 __ ret(0); | |
135 | |
136 // Dictionary load failed, go slow (but don't miss). | |
137 __ bind(&slow); | |
138 GenerateRuntimeGetProperty(masm); | |
139 } | |
140 | |
141 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | |
142 // Return address is on the stack. | |
143 Register receiver = LoadDescriptor::ReceiverRegister(); | |
144 Register name = LoadDescriptor::NameRegister(); | |
145 DCHECK(!ebx.is(receiver) && !ebx.is(name)); | |
146 | |
147 __ pop(ebx); | |
148 __ push(receiver); | |
149 __ push(name); | |
150 __ push(ebx); | |
151 | |
152 // Do tail-call to runtime routine. | |
153 __ TailCallRuntime(Runtime::kGetProperty); | |
154 } | |
155 | |
156 static void StoreIC_PushArgs(MacroAssembler* masm) { | 21 static void StoreIC_PushArgs(MacroAssembler* masm) { |
157 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); | 22 Register receiver = StoreWithVectorDescriptor::ReceiverRegister(); |
158 Register name = StoreWithVectorDescriptor::NameRegister(); | 23 Register name = StoreWithVectorDescriptor::NameRegister(); |
159 | 24 |
160 STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3); | 25 STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 3); |
161 // Current stack layout: | 26 // Current stack layout: |
162 // - esp[12] -- value | 27 // - esp[12] -- value |
163 // - esp[8] -- slot | 28 // - esp[8] -- slot |
164 // - esp[4] -- vector | 29 // - esp[4] -- vector |
165 // - esp[0] -- return address | 30 // - esp[0] -- return address |
166 | 31 |
167 Register return_address = StoreWithVectorDescriptor::SlotRegister(); | 32 Register return_address = StoreWithVectorDescriptor::SlotRegister(); |
168 __ pop(return_address); | 33 __ pop(return_address); |
169 __ push(receiver); | 34 __ push(receiver); |
170 __ push(name); | 35 __ push(name); |
171 __ push(return_address); | 36 __ push(return_address); |
172 } | 37 } |
173 | 38 |
174 | |
175 void StoreIC::GenerateMiss(MacroAssembler* masm) { | |
176 // Return address is on the stack. | |
177 StoreIC_PushArgs(masm); | |
178 | |
179 // Perform tail call to the entry. | |
180 __ TailCallRuntime(Runtime::kStoreIC_Miss); | |
181 } | |
182 | |
183 | |
184 void StoreIC::GenerateNormal(MacroAssembler* masm) { | |
185 typedef StoreWithVectorDescriptor Descriptor; | |
186 Label restore_miss; | |
187 Register receiver = Descriptor::ReceiverRegister(); | |
188 Register name = Descriptor::NameRegister(); | |
189 Register value = Descriptor::ValueRegister(); | |
190 // Since the slot and vector values are passed on the stack we can use | |
191 // respective registers as scratch registers. | |
192 Register scratch1 = Descriptor::VectorRegister(); | |
193 Register scratch2 = Descriptor::SlotRegister(); | |
194 | |
195 __ LoadParameterFromStack<Descriptor>(value, Descriptor::kValue); | |
196 | |
197 // A lot of registers are needed for storing to slow case objects. | |
198 // Push and restore receiver but rely on GenerateDictionaryStore preserving | |
199 // the value and name. | |
200 __ push(receiver); | |
201 | |
202 Register dictionary = receiver; | |
203 __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset)); | |
204 GenerateDictionaryStore(masm, &restore_miss, dictionary, name, value, | |
205 scratch1, scratch2); | |
206 __ Drop(1); | |
207 Counters* counters = masm->isolate()->counters(); | |
208 __ IncrementCounter(counters->ic_store_normal_hit(), 1); | |
209 __ ret(Descriptor::kStackArgumentsCount * kPointerSize); | |
210 | |
211 __ bind(&restore_miss); | |
212 __ pop(receiver); | |
213 __ IncrementCounter(counters->ic_store_normal_miss(), 1); | |
214 GenerateMiss(masm); | |
215 } | |
216 | |
217 | |
218 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 39 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
219 // Return address is on the stack. | 40 // Return address is on the stack. |
220 StoreIC_PushArgs(masm); | 41 StoreIC_PushArgs(masm); |
221 | 42 |
222 // Do tail-call to runtime routine. | 43 // Do tail-call to runtime routine. |
223 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); | 44 __ TailCallRuntime(Runtime::kKeyedStoreIC_Miss); |
224 } | 45 } |
225 | 46 |
226 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { | 47 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) { |
227 // Return address is on the stack. | 48 // Return address is on the stack. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 Condition cc = | 121 Condition cc = |
301 (check == ENABLE_INLINED_SMI_CHECK) | 122 (check == ENABLE_INLINED_SMI_CHECK) |
302 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) | 123 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero) |
303 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); | 124 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry); |
304 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); | 125 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc); |
305 } | 126 } |
306 } // namespace internal | 127 } // namespace internal |
307 } // namespace v8 | 128 } // namespace v8 |
308 | 129 |
309 #endif // V8_TARGET_ARCH_X87 | 130 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |