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_ARM | 5 #if V8_TARGET_ARCH_ARM |
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 // ---------------------------------------------------------------------------- | 16 // ---------------------------------------------------------------------------- |
17 // Static IC stub generators. | 17 // Static IC stub generators. |
18 // | 18 // |
19 | 19 |
20 #define __ ACCESS_MASM(masm) | 20 #define __ ACCESS_MASM(masm) |
21 | 21 |
22 | |
23 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type, | |
24 Label* global_object) { | |
25 // Register usage: | |
26 // type: holds the receiver instance type on entry. | |
27 __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE)); | |
28 __ b(eq, global_object); | |
29 __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE)); | |
30 __ b(eq, global_object); | |
31 } | |
32 | |
33 | |
34 // Helper function used from LoadIC GenerateNormal. | 22 // Helper function used from LoadIC GenerateNormal. |
35 // | 23 // |
36 // elements: Property dictionary. It is not clobbered if a jump to the miss | 24 // elements: Property dictionary. It is not clobbered if a jump to the miss |
37 // label is done. | 25 // label is done. |
38 // name: Property name. It is not clobbered if a jump to the miss label is | 26 // name: Property name. It is not clobbered if a jump to the miss label is |
39 // done | 27 // done |
40 // result: Register for the result. It is only updated if a jump to the miss | 28 // result: Register for the result. It is only updated if a jump to the miss |
41 // label is not done. Can be the same as elements or name clobbering | 29 // label is not done. Can be the same as elements or name clobbering |
42 // one of these in the case of not jumping to the miss label. | 30 // one of these in the case of not jumping to the miss label. |
43 // The two scratch registers need to be different from elements, name and | 31 // The two scratch registers need to be different from elements, name and |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 const int kValueOffset = kElementsStartOffset + kPointerSize; | 107 const int kValueOffset = kElementsStartOffset + kPointerSize; |
120 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); | 108 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag)); |
121 __ str(value, MemOperand(scratch2)); | 109 __ str(value, MemOperand(scratch2)); |
122 | 110 |
123 // Update the write barrier. Make sure not to clobber the value. | 111 // Update the write barrier. Make sure not to clobber the value. |
124 __ mov(scratch1, value); | 112 __ mov(scratch1, value); |
125 __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved, | 113 __ RecordWrite(elements, scratch2, scratch1, kLRHasNotBeenSaved, |
126 kDontSaveFPRegs); | 114 kDontSaveFPRegs); |
127 } | 115 } |
128 | 116 |
129 | |
130 // Checks the receiver for special cases (value type, slow case bits). | |
131 // Falls through for regular JS object. | |
132 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm, | |
133 Register receiver, Register map, | |
134 Register scratch, | |
135 int interceptor_bit, Label* slow) { | |
136 // Check that the object isn't a smi. | |
137 __ JumpIfSmi(receiver, slow); | |
138 // Get the map of the receiver. | |
139 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
140 // Check bit field. | |
141 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset)); | |
142 __ tst(scratch, | |
143 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit))); | |
144 __ b(ne, slow); | |
145 // Check that the object is some kind of JS object EXCEPT JS Value type. | |
146 // In the case that the object is a value-wrapper object, | |
147 // we enter the runtime system to make sure that indexing into string | |
148 // objects work as intended. | |
149 DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE); | |
150 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset)); | |
151 __ cmp(scratch, Operand(JS_OBJECT_TYPE)); | |
152 __ b(lt, slow); | |
153 } | |
154 | |
155 | |
156 // Loads an indexed element from a fast case array. | |
157 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver, | |
158 Register key, Register elements, | |
159 Register scratch1, Register scratch2, | |
160 Register result, Label* slow) { | |
161 // Register use: | |
162 // | |
163 // receiver - holds the receiver on entry. | |
164 // Unchanged unless 'result' is the same register. | |
165 // | |
166 // key - holds the smi key on entry. | |
167 // Unchanged unless 'result' is the same register. | |
168 // | |
169 // result - holds the result on exit if the load succeeded. | |
170 // Allowed to be the the same as 'receiver' or 'key'. | |
171 // Unchanged on bailout so 'receiver' and 'key' can be safely | |
172 // used by further computation. | |
173 // | |
174 // Scratch registers: | |
175 // | |
176 // elements - holds the elements of the receiver and its prototypes. | |
177 // | |
178 // scratch1 - used to hold elements length, bit fields, base addresses. | |
179 // | |
180 // scratch2 - used to hold maps, prototypes, and the loaded value. | |
181 Label check_prototypes, check_next_prototype; | |
182 Label done, in_bounds, absent; | |
183 | |
184 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
185 __ AssertFastElements(elements); | |
186 | |
187 // Check that the key (index) is within bounds. | |
188 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
189 __ cmp(key, Operand(scratch1)); | |
190 __ b(lo, &in_bounds); | |
191 // Out-of-bounds. Check the prototype chain to see if we can just return | |
192 // 'undefined'. | |
193 __ cmp(key, Operand(0)); | |
194 __ b(lt, slow); // Negative keys can't take the fast OOB path. | |
195 __ bind(&check_prototypes); | |
196 __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
197 __ bind(&check_next_prototype); | |
198 __ ldr(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset)); | |
199 // scratch2: current prototype | |
200 __ CompareRoot(scratch2, Heap::kNullValueRootIndex); | |
201 __ b(eq, &absent); | |
202 __ ldr(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset)); | |
203 __ ldr(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset)); | |
204 // elements: elements of current prototype | |
205 // scratch2: map of current prototype | |
206 __ CompareInstanceType(scratch2, scratch1, JS_OBJECT_TYPE); | |
207 __ b(lo, slow); | |
208 __ ldrb(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset)); | |
209 __ tst(scratch1, Operand((1 << Map::kIsAccessCheckNeeded) | | |
210 (1 << Map::kHasIndexedInterceptor))); | |
211 __ b(ne, slow); | |
212 __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex); | |
213 __ b(ne, slow); | |
214 __ jmp(&check_next_prototype); | |
215 | |
216 __ bind(&absent); | |
217 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); | |
218 __ jmp(&done); | |
219 | |
220 __ bind(&in_bounds); | |
221 // Fast case: Do the load. | |
222 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
223 __ ldr(scratch2, MemOperand::PointerAddressFromSmiKey(scratch1, key)); | |
224 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex); | |
225 // In case the loaded value is the_hole we have to check the prototype chain. | |
226 __ b(eq, &check_prototypes); | |
227 __ mov(result, scratch2); | |
228 __ bind(&done); | |
229 } | |
230 | |
231 | |
232 // Checks whether a key is an array index string or a unique name. | |
233 // Falls through if a key is a unique name. | |
234 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key, | |
235 Register map, Register hash, | |
236 Label* index_string, Label* not_unique) { | |
237 // The key is not a smi. | |
238 Label unique; | |
239 // Is it a name? | |
240 __ CompareObjectType(key, map, hash, LAST_UNIQUE_NAME_TYPE); | |
241 __ b(hi, not_unique); | |
242 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE); | |
243 __ b(eq, &unique); | |
244 | |
245 // Is the string an array index, with cached numeric value? | |
246 __ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset)); | |
247 __ tst(hash, Operand(Name::kContainsCachedArrayIndexMask)); | |
248 __ b(eq, index_string); | |
249 | |
250 // Is the string internalized? We know it's a string, so a single | |
251 // bit test is enough. | |
252 // map: key map | |
253 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset)); | |
254 STATIC_ASSERT(kInternalizedTag == 0); | |
255 __ tst(hash, Operand(kIsNotInternalizedMask)); | |
256 __ b(ne, not_unique); | |
257 | |
258 __ bind(&unique); | |
259 } | |
260 | |
261 void LoadIC::GenerateNormal(MacroAssembler* masm) { | 117 void LoadIC::GenerateNormal(MacroAssembler* masm) { |
262 Register dictionary = r0; | 118 Register dictionary = r0; |
263 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); | 119 DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister())); |
264 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); | 120 DCHECK(!dictionary.is(LoadDescriptor::NameRegister())); |
265 | 121 |
266 Label slow; | 122 Label slow; |
267 | 123 |
268 __ ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(), | 124 __ ldr(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(), |
269 JSObject::kPropertiesOffset)); | 125 JSObject::kPropertiesOffset)); |
270 GenerateDictionaryLoad(masm, &slow, dictionary, | 126 GenerateDictionaryLoad(masm, &slow, dictionary, |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { | 189 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) { |
334 // The return address is in lr. | 190 // The return address is in lr. |
335 | 191 |
336 __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); | 192 __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister()); |
337 | 193 |
338 // Perform tail call to the entry. | 194 // Perform tail call to the entry. |
339 // Do tail-call to runtime routine. | 195 // Do tail-call to runtime routine. |
340 __ TailCallRuntime(Runtime::kKeyedGetProperty); | 196 __ TailCallRuntime(Runtime::kKeyedGetProperty); |
341 } | 197 } |
342 | 198 |
343 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) { | |
344 // The return address is in lr. | |
345 Label slow, check_name, index_smi, index_name, property_array_property; | |
346 Label probe_dictionary, check_number_dictionary; | |
347 | |
348 Register key = LoadDescriptor::NameRegister(); | |
349 Register receiver = LoadDescriptor::ReceiverRegister(); | |
350 DCHECK(key.is(r2)); | |
351 DCHECK(receiver.is(r1)); | |
352 | |
353 Isolate* isolate = masm->isolate(); | |
354 | |
355 // Check that the key is a smi. | |
356 __ JumpIfNotSmi(key, &check_name); | |
357 __ bind(&index_smi); | |
358 // Now the key is known to be a smi. This place is also jumped to from below | |
359 // where a numeric string is converted to a smi. | |
360 | |
361 GenerateKeyedLoadReceiverCheck(masm, receiver, r0, r3, | |
362 Map::kHasIndexedInterceptor, &slow); | |
363 | |
364 // Check the receiver's map to see if it has fast elements. | |
365 __ CheckFastElements(r0, r3, &check_number_dictionary); | |
366 | |
367 GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, &slow); | |
368 __ IncrementCounter(isolate->counters()->ic_keyed_load_generic_smi(), 1, r4, | |
369 r3); | |
370 __ Ret(); | |
371 | |
372 __ bind(&check_number_dictionary); | |
373 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
374 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset)); | |
375 | |
376 // Check whether the elements is a number dictionary. | |
377 // r3: elements map | |
378 // r4: elements | |
379 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | |
380 __ cmp(r3, ip); | |
381 __ b(ne, &slow); | |
382 __ SmiUntag(r0, key); | |
383 __ LoadFromNumberDictionary(&slow, r4, key, r0, r0, r3, r5); | |
384 __ Ret(); | |
385 | |
386 // Slow case, key and receiver still in r2 and r1. | |
387 __ bind(&slow); | |
388 __ IncrementCounter(isolate->counters()->ic_keyed_load_generic_slow(), 1, r4, | |
389 r3); | |
390 GenerateRuntimeGetProperty(masm); | |
391 | |
392 __ bind(&check_name); | |
393 GenerateKeyNameCheck(masm, key, r0, r3, &index_name, &slow); | |
394 | |
395 GenerateKeyedLoadReceiverCheck(masm, receiver, r0, r3, | |
396 Map::kHasNamedInterceptor, &slow); | |
397 | |
398 // If the receiver is a fast-case object, check the stub cache. Otherwise | |
399 // probe the dictionary. | |
400 __ ldr(r3, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | |
401 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset)); | |
402 __ LoadRoot(ip, Heap::kHashTableMapRootIndex); | |
403 __ cmp(r4, ip); | |
404 __ b(eq, &probe_dictionary); | |
405 | |
406 // The handlers in the stub cache expect a vector and slot. Since we won't | |
407 // change the IC from any downstream misses, a dummy vector can be used. | |
408 Register vector = LoadWithVectorDescriptor::VectorRegister(); | |
409 Register slot = LoadWithVectorDescriptor::SlotRegister(); | |
410 DCHECK(!AreAliased(vector, slot, r4, r5, r6, r9)); | |
411 Handle<TypeFeedbackVector> dummy_vector = | |
412 TypeFeedbackVector::DummyVector(masm->isolate()); | |
413 int slot_index = dummy_vector->GetIndex( | |
414 FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedLoadICSlot)); | |
415 __ LoadRoot(vector, Heap::kDummyVectorRootIndex); | |
416 __ mov(slot, Operand(Smi::FromInt(slot_index))); | |
417 | |
418 masm->isolate()->load_stub_cache()->GenerateProbe(masm, receiver, key, r4, r5, | |
419 r6, r9); | |
420 // Cache miss. | |
421 GenerateMiss(masm); | |
422 | |
423 // Do a quick inline probe of the receiver's dictionary, if it | |
424 // exists. | |
425 __ bind(&probe_dictionary); | |
426 // r3: elements | |
427 __ ldr(r0, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
428 __ ldrb(r0, FieldMemOperand(r0, Map::kInstanceTypeOffset)); | |
429 GenerateGlobalInstanceTypeCheck(masm, r0, &slow); | |
430 // Load the property to r0. | |
431 GenerateDictionaryLoad(masm, &slow, r3, key, r0, r5, r4); | |
432 __ IncrementCounter(isolate->counters()->ic_keyed_load_generic_symbol(), 1, | |
433 r4, r3); | |
434 __ Ret(); | |
435 | |
436 __ bind(&index_name); | |
437 __ IndexFromHash(r3, key); | |
438 // Now jump to the place where smi keys are handled. | |
439 __ jmp(&index_smi); | |
440 } | |
441 | |
442 | |
443 static void StoreIC_PushArgs(MacroAssembler* masm) { | 199 static void StoreIC_PushArgs(MacroAssembler* masm) { |
444 __ Push(StoreWithVectorDescriptor::ValueRegister(), | 200 __ Push(StoreWithVectorDescriptor::ValueRegister(), |
445 StoreWithVectorDescriptor::SlotRegister(), | 201 StoreWithVectorDescriptor::SlotRegister(), |
446 StoreWithVectorDescriptor::VectorRegister(), | 202 StoreWithVectorDescriptor::VectorRegister(), |
447 StoreWithVectorDescriptor::ReceiverRegister(), | 203 StoreWithVectorDescriptor::ReceiverRegister(), |
448 StoreWithVectorDescriptor::NameRegister()); | 204 StoreWithVectorDescriptor::NameRegister()); |
449 } | 205 } |
450 | 206 |
451 | 207 |
452 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { | 208 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) { |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 patcher.EmitCondition(ne); | 620 patcher.EmitCondition(ne); |
865 } else { | 621 } else { |
866 DCHECK(Assembler::GetCondition(branch_instr) == ne); | 622 DCHECK(Assembler::GetCondition(branch_instr) == ne); |
867 patcher.EmitCondition(eq); | 623 patcher.EmitCondition(eq); |
868 } | 624 } |
869 } | 625 } |
870 } // namespace internal | 626 } // namespace internal |
871 } // namespace v8 | 627 } // namespace v8 |
872 | 628 |
873 #endif // V8_TARGET_ARCH_ARM | 629 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |