Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: src/ic/arm/ic-arm.cc

Issue 2424433002: [ic] Delete old KeyedLoadIC code (Closed)
Patch Set: fix failing test Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/ic/arm64/ic-arm64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/ic/arm64/ic-arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698