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

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

Issue 483683005: Move IC code into a subdir and move ic-compilation related code from stub-cache into ic-compiler (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix BUILD.gn Created 6 years, 4 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 | Annotate | Revision Log
« no previous file with comments | « src/arm64/full-codegen-arm64.cc ('k') | src/arm64/lithium-codegen-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
(Empty)
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_ARM64
8
9 #include "src/arm64/assembler-arm64.h"
10 #include "src/code-stubs.h"
11 #include "src/codegen.h"
12 #include "src/disasm.h"
13 #include "src/ic-inl.h"
14 #include "src/runtime.h"
15 #include "src/stub-cache.h"
16
17 namespace v8 {
18 namespace internal {
19
20
21 #define __ ACCESS_MASM(masm)
22
23
24 // "type" holds an instance type on entry and is not clobbered.
25 // Generated code branch on "global_object" if type is any kind of global
26 // JS object.
27 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
28 Register type,
29 Label* global_object) {
30 __ Cmp(type, JS_GLOBAL_OBJECT_TYPE);
31 __ Ccmp(type, JS_BUILTINS_OBJECT_TYPE, ZFlag, ne);
32 __ Ccmp(type, JS_GLOBAL_PROXY_TYPE, ZFlag, ne);
33 __ B(eq, global_object);
34 }
35
36
37 // Helper function used from LoadIC GenerateNormal.
38 //
39 // elements: Property dictionary. It is not clobbered if a jump to the miss
40 // label is done.
41 // name: Property name. It is not clobbered if a jump to the miss label is
42 // done
43 // result: Register for the result. It is only updated if a jump to the miss
44 // label is not done.
45 // The scratch registers need to be different from elements, name and result.
46 // The generated code assumes that the receiver has slow properties,
47 // is not a global object and does not have interceptors.
48 static void GenerateDictionaryLoad(MacroAssembler* masm,
49 Label* miss,
50 Register elements,
51 Register name,
52 Register result,
53 Register scratch1,
54 Register scratch2) {
55 DCHECK(!AreAliased(elements, name, scratch1, scratch2));
56 DCHECK(!AreAliased(result, scratch1, scratch2));
57
58 Label done;
59
60 // Probe the dictionary.
61 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
62 miss,
63 &done,
64 elements,
65 name,
66 scratch1,
67 scratch2);
68
69 // If probing finds an entry check that the value is a normal property.
70 __ Bind(&done);
71
72 static const int kElementsStartOffset = NameDictionary::kHeaderSize +
73 NameDictionary::kElementsStartIndex * kPointerSize;
74 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
75 __ Ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
76 __ Tst(scratch1, Smi::FromInt(PropertyDetails::TypeField::kMask));
77 __ B(ne, miss);
78
79 // Get the value at the masked, scaled index and return.
80 __ Ldr(result,
81 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
82 }
83
84
85 // Helper function used from StoreIC::GenerateNormal.
86 //
87 // elements: Property dictionary. It is not clobbered if a jump to the miss
88 // label is done.
89 // name: Property name. It is not clobbered if a jump to the miss label is
90 // done
91 // value: The value to store (never clobbered).
92 //
93 // The generated code assumes that the receiver has slow properties,
94 // is not a global object and does not have interceptors.
95 static void GenerateDictionaryStore(MacroAssembler* masm,
96 Label* miss,
97 Register elements,
98 Register name,
99 Register value,
100 Register scratch1,
101 Register scratch2) {
102 DCHECK(!AreAliased(elements, name, value, scratch1, scratch2));
103
104 Label done;
105
106 // Probe the dictionary.
107 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
108 miss,
109 &done,
110 elements,
111 name,
112 scratch1,
113 scratch2);
114
115 // If probing finds an entry in the dictionary check that the value
116 // is a normal property that is not read only.
117 __ Bind(&done);
118
119 static const int kElementsStartOffset = NameDictionary::kHeaderSize +
120 NameDictionary::kElementsStartIndex * kPointerSize;
121 static const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
122 static const int kTypeAndReadOnlyMask =
123 PropertyDetails::TypeField::kMask |
124 PropertyDetails::AttributesField::encode(READ_ONLY);
125 __ Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
126 __ Tst(scratch1, kTypeAndReadOnlyMask);
127 __ B(ne, miss);
128
129 // Store the value at the masked, scaled index and return.
130 static const int kValueOffset = kElementsStartOffset + kPointerSize;
131 __ Add(scratch2, scratch2, kValueOffset - kHeapObjectTag);
132 __ Str(value, MemOperand(scratch2));
133
134 // Update the write barrier. Make sure not to clobber the value.
135 __ Mov(scratch1, value);
136 __ RecordWrite(
137 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs);
138 }
139
140
141 // Checks the receiver for special cases (value type, slow case bits).
142 // Falls through for regular JS object and return the map of the
143 // receiver in 'map_scratch' if the receiver is not a SMI.
144 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
145 Register receiver,
146 Register map_scratch,
147 Register scratch,
148 int interceptor_bit,
149 Label* slow) {
150 DCHECK(!AreAliased(map_scratch, scratch));
151
152 // Check that the object isn't a smi.
153 __ JumpIfSmi(receiver, slow);
154 // Get the map of the receiver.
155 __ Ldr(map_scratch, FieldMemOperand(receiver, HeapObject::kMapOffset));
156 // Check bit field.
157 __ Ldrb(scratch, FieldMemOperand(map_scratch, Map::kBitFieldOffset));
158 __ Tbnz(scratch, Map::kIsAccessCheckNeeded, slow);
159 __ Tbnz(scratch, interceptor_bit, slow);
160
161 // Check that the object is some kind of JS object EXCEPT JS Value type.
162 // In the case that the object is a value-wrapper object, we enter the
163 // runtime system to make sure that indexing into string objects work
164 // as intended.
165 STATIC_ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
166 __ Ldrb(scratch, FieldMemOperand(map_scratch, Map::kInstanceTypeOffset));
167 __ Cmp(scratch, JS_OBJECT_TYPE);
168 __ B(lt, slow);
169 }
170
171
172 // Loads an indexed element from a fast case array.
173 // If not_fast_array is NULL, doesn't perform the elements map check.
174 //
175 // receiver - holds the receiver on entry.
176 // Unchanged unless 'result' is the same register.
177 //
178 // key - holds the smi key on entry.
179 // Unchanged unless 'result' is the same register.
180 //
181 // elements - holds the elements of the receiver on exit.
182 //
183 // elements_map - holds the elements map on exit if the not_fast_array branch is
184 // taken. Otherwise, this is used as a scratch register.
185 //
186 // result - holds the result on exit if the load succeeded.
187 // Allowed to be the the same as 'receiver' or 'key'.
188 // Unchanged on bailout so 'receiver' and 'key' can be safely
189 // used by further computation.
190 static void GenerateFastArrayLoad(MacroAssembler* masm,
191 Register receiver,
192 Register key,
193 Register elements,
194 Register elements_map,
195 Register scratch2,
196 Register result,
197 Label* not_fast_array,
198 Label* slow) {
199 DCHECK(!AreAliased(receiver, key, elements, elements_map, scratch2));
200
201 // Check for fast array.
202 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
203 if (not_fast_array != NULL) {
204 // Check that the object is in fast mode and writable.
205 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
206 __ JumpIfNotRoot(elements_map, Heap::kFixedArrayMapRootIndex,
207 not_fast_array);
208 } else {
209 __ AssertFastElements(elements);
210 }
211
212 // The elements_map register is only used for the not_fast_array path, which
213 // was handled above. From this point onward it is a scratch register.
214 Register scratch1 = elements_map;
215
216 // Check that the key (index) is within bounds.
217 __ Ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
218 __ Cmp(key, scratch1);
219 __ B(hs, slow);
220
221 // Fast case: Do the load.
222 __ Add(scratch1, elements, FixedArray::kHeaderSize - kHeapObjectTag);
223 __ SmiUntag(scratch2, key);
224 __ Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
225
226 // In case the loaded value is the_hole we have to consult GetProperty
227 // to ensure the prototype chain is searched.
228 __ JumpIfRoot(scratch2, Heap::kTheHoleValueRootIndex, slow);
229
230 // Move the value to the result register.
231 // 'result' can alias with 'receiver' or 'key' but these two must be
232 // preserved if we jump to 'slow'.
233 __ Mov(result, scratch2);
234 }
235
236
237 // Checks whether a key is an array index string or a unique name.
238 // Falls through if a key is a unique name.
239 // The map of the key is returned in 'map_scratch'.
240 // If the jump to 'index_string' is done the hash of the key is left
241 // in 'hash_scratch'.
242 static void GenerateKeyNameCheck(MacroAssembler* masm,
243 Register key,
244 Register map_scratch,
245 Register hash_scratch,
246 Label* index_string,
247 Label* not_unique) {
248 DCHECK(!AreAliased(key, map_scratch, hash_scratch));
249
250 // Is the key a name?
251 Label unique;
252 __ JumpIfObjectType(key, map_scratch, hash_scratch, LAST_UNIQUE_NAME_TYPE,
253 not_unique, hi);
254 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
255 __ B(eq, &unique);
256
257 // Is the string an array index with cached numeric value?
258 __ Ldr(hash_scratch.W(), FieldMemOperand(key, Name::kHashFieldOffset));
259 __ TestAndBranchIfAllClear(hash_scratch,
260 Name::kContainsCachedArrayIndexMask,
261 index_string);
262
263 // Is the string internalized? We know it's a string, so a single bit test is
264 // enough.
265 __ Ldrb(hash_scratch, FieldMemOperand(map_scratch, Map::kInstanceTypeOffset));
266 STATIC_ASSERT(kInternalizedTag == 0);
267 __ TestAndBranchIfAnySet(hash_scratch, kIsNotInternalizedMask, not_unique);
268
269 __ Bind(&unique);
270 // Fall through if the key is a unique name.
271 }
272
273
274 // Neither 'object' nor 'key' are modified by this function.
275 //
276 // If the 'unmapped_case' or 'slow_case' exit is taken, the 'map' register is
277 // left with the object's elements map. Otherwise, it is used as a scratch
278 // register.
279 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
280 Register object,
281 Register key,
282 Register map,
283 Register scratch1,
284 Register scratch2,
285 Label* unmapped_case,
286 Label* slow_case) {
287 DCHECK(!AreAliased(object, key, map, scratch1, scratch2));
288
289 Heap* heap = masm->isolate()->heap();
290
291 // Check that the receiver is a JSObject. Because of the elements
292 // map check later, we do not need to check for interceptors or
293 // whether it requires access checks.
294 __ JumpIfSmi(object, slow_case);
295 // Check that the object is some kind of JSObject.
296 __ JumpIfObjectType(object, map, scratch1, FIRST_JS_RECEIVER_TYPE,
297 slow_case, lt);
298
299 // Check that the key is a positive smi.
300 __ JumpIfNotSmi(key, slow_case);
301 __ Tbnz(key, kXSignBit, slow_case);
302
303 // Load the elements object and check its map.
304 Handle<Map> arguments_map(heap->sloppy_arguments_elements_map());
305 __ Ldr(map, FieldMemOperand(object, JSObject::kElementsOffset));
306 __ CheckMap(map, scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
307
308 // Check if element is in the range of mapped arguments. If not, jump
309 // to the unmapped lookup.
310 __ Ldr(scratch1, FieldMemOperand(map, FixedArray::kLengthOffset));
311 __ Sub(scratch1, scratch1, Smi::FromInt(2));
312 __ Cmp(key, scratch1);
313 __ B(hs, unmapped_case);
314
315 // Load element index and check whether it is the hole.
316 static const int offset =
317 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
318
319 __ Add(scratch1, map, offset);
320 __ SmiUntag(scratch2, key);
321 __ Ldr(scratch1, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
322 __ JumpIfRoot(scratch1, Heap::kTheHoleValueRootIndex, unmapped_case);
323
324 // Load value from context and return it.
325 __ Ldr(scratch2, FieldMemOperand(map, FixedArray::kHeaderSize));
326 __ SmiUntag(scratch1);
327 __ Lsl(scratch1, scratch1, kPointerSizeLog2);
328 __ Add(scratch1, scratch1, Context::kHeaderSize - kHeapObjectTag);
329 // The base of the result (scratch2) is passed to RecordWrite in
330 // KeyedStoreIC::GenerateSloppyArguments and it must be a HeapObject.
331 return MemOperand(scratch2, scratch1);
332 }
333
334
335 // The 'parameter_map' register must be loaded with the parameter map of the
336 // arguments object and is overwritten.
337 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
338 Register key,
339 Register parameter_map,
340 Register scratch,
341 Label* slow_case) {
342 DCHECK(!AreAliased(key, parameter_map, scratch));
343
344 // Element is in arguments backing store, which is referenced by the
345 // second element of the parameter_map.
346 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
347 Register backing_store = parameter_map;
348 __ Ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
349 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
350 __ CheckMap(
351 backing_store, scratch, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
352 __ Ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
353 __ Cmp(key, scratch);
354 __ B(hs, slow_case);
355
356 __ Add(backing_store,
357 backing_store,
358 FixedArray::kHeaderSize - kHeapObjectTag);
359 __ SmiUntag(scratch, key);
360 return MemOperand(backing_store, scratch, LSL, kPointerSizeLog2);
361 }
362
363
364 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
365 // The return address is in lr.
366 Register receiver = ReceiverRegister();
367 Register name = NameRegister();
368 DCHECK(receiver.is(x1));
369 DCHECK(name.is(x2));
370
371 // Probe the stub cache.
372 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
373 Code::ComputeHandlerFlags(Code::LOAD_IC));
374 masm->isolate()->stub_cache()->GenerateProbe(
375 masm, flags, receiver, name, x3, x4, x5, x6);
376
377 // Cache miss: Jump to runtime.
378 GenerateMiss(masm);
379 }
380
381
382 void LoadIC::GenerateNormal(MacroAssembler* masm) {
383 Register dictionary = x0;
384 DCHECK(!dictionary.is(ReceiverRegister()));
385 DCHECK(!dictionary.is(NameRegister()));
386 Label slow;
387
388 __ Ldr(dictionary,
389 FieldMemOperand(ReceiverRegister(), JSObject::kPropertiesOffset));
390 GenerateDictionaryLoad(masm, &slow, dictionary, NameRegister(), x0, x3, x4);
391 __ Ret();
392
393 // Dictionary load failed, go slow (but don't miss).
394 __ Bind(&slow);
395 GenerateRuntimeGetProperty(masm);
396 }
397
398
399 void LoadIC::GenerateMiss(MacroAssembler* masm) {
400 // The return address is in lr.
401 Isolate* isolate = masm->isolate();
402 ASM_LOCATION("LoadIC::GenerateMiss");
403
404 __ IncrementCounter(isolate->counters()->load_miss(), 1, x3, x4);
405
406 // Perform tail call to the entry.
407 __ Push(ReceiverRegister(), NameRegister());
408 ExternalReference ref =
409 ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
410 __ TailCallExternalReference(ref, 2, 1);
411 }
412
413
414 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
415 // The return address is in lr.
416 __ Push(ReceiverRegister(), NameRegister());
417 __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
418 }
419
420
421 void KeyedLoadIC::GenerateSloppyArguments(MacroAssembler* masm) {
422 // The return address is in lr.
423 Register result = x0;
424 Register receiver = ReceiverRegister();
425 Register key = NameRegister();
426 DCHECK(receiver.is(x1));
427 DCHECK(key.is(x2));
428
429 Label miss, unmapped;
430
431 Register map_scratch = x0;
432 MemOperand mapped_location = GenerateMappedArgumentsLookup(
433 masm, receiver, key, map_scratch, x3, x4, &unmapped, &miss);
434 __ Ldr(result, mapped_location);
435 __ Ret();
436
437 __ Bind(&unmapped);
438 // Parameter map is left in map_scratch when a jump on unmapped is done.
439 MemOperand unmapped_location =
440 GenerateUnmappedArgumentsLookup(masm, key, map_scratch, x3, &miss);
441 __ Ldr(result, unmapped_location);
442 __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
443 __ Ret();
444
445 __ Bind(&miss);
446 GenerateMiss(masm);
447 }
448
449
450 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
451 ASM_LOCATION("KeyedStoreIC::GenerateSloppyArguments");
452 Label slow, notin;
453 Register value = ValueRegister();
454 Register key = NameRegister();
455 Register receiver = ReceiverRegister();
456 DCHECK(receiver.is(x1));
457 DCHECK(key.is(x2));
458 DCHECK(value.is(x0));
459
460 Register map = x3;
461
462 // These registers are used by GenerateMappedArgumentsLookup to build a
463 // MemOperand. They are live for as long as the MemOperand is live.
464 Register mapped1 = x4;
465 Register mapped2 = x5;
466
467 MemOperand mapped =
468 GenerateMappedArgumentsLookup(masm, receiver, key, map,
469 mapped1, mapped2,
470 &notin, &slow);
471 Operand mapped_offset = mapped.OffsetAsOperand();
472 __ Str(value, mapped);
473 __ Add(x10, mapped.base(), mapped_offset);
474 __ Mov(x11, value);
475 __ RecordWrite(mapped.base(), x10, x11, kLRHasNotBeenSaved, kDontSaveFPRegs);
476 __ Ret();
477
478 __ Bind(&notin);
479
480 // These registers are used by GenerateMappedArgumentsLookup to build a
481 // MemOperand. They are live for as long as the MemOperand is live.
482 Register unmapped1 = map; // This is assumed to alias 'map'.
483 Register unmapped2 = x4;
484 MemOperand unmapped =
485 GenerateUnmappedArgumentsLookup(masm, key, unmapped1, unmapped2, &slow);
486 Operand unmapped_offset = unmapped.OffsetAsOperand();
487 __ Str(value, unmapped);
488 __ Add(x10, unmapped.base(), unmapped_offset);
489 __ Mov(x11, value);
490 __ RecordWrite(unmapped.base(), x10, x11,
491 kLRHasNotBeenSaved, kDontSaveFPRegs);
492 __ Ret();
493 __ Bind(&slow);
494 GenerateMiss(masm);
495 }
496
497
498 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
499 // The return address is in lr.
500 Isolate* isolate = masm->isolate();
501
502 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, x10, x11);
503
504 __ Push(ReceiverRegister(), NameRegister());
505
506 // Perform tail call to the entry.
507 ExternalReference ref =
508 ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
509
510 __ TailCallExternalReference(ref, 2, 1);
511 }
512
513
514 // IC register specifications
515 const Register LoadIC::ReceiverRegister() { return x1; }
516 const Register LoadIC::NameRegister() { return x2; }
517
518 const Register LoadIC::SlotRegister() {
519 DCHECK(FLAG_vector_ics);
520 return x0;
521 }
522
523
524 const Register LoadIC::VectorRegister() {
525 DCHECK(FLAG_vector_ics);
526 return x3;
527 }
528
529
530 const Register StoreIC::ReceiverRegister() { return x1; }
531 const Register StoreIC::NameRegister() { return x2; }
532 const Register StoreIC::ValueRegister() { return x0; }
533
534
535 const Register KeyedStoreIC::MapRegister() {
536 return x3;
537 }
538
539
540 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
541 // The return address is in lr.
542 __ Push(ReceiverRegister(), NameRegister());
543 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
544 }
545
546
547 static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm,
548 Register key,
549 Register receiver,
550 Register scratch1,
551 Register scratch2,
552 Register scratch3,
553 Register scratch4,
554 Register scratch5,
555 Label *slow) {
556 DCHECK(!AreAliased(
557 key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5));
558
559 Isolate* isolate = masm->isolate();
560 Label check_number_dictionary;
561 // If we can load the value, it should be returned in x0.
562 Register result = x0;
563
564 GenerateKeyedLoadReceiverCheck(
565 masm, receiver, scratch1, scratch2, Map::kHasIndexedInterceptor, slow);
566
567 // Check the receiver's map to see if it has fast elements.
568 __ CheckFastElements(scratch1, scratch2, &check_number_dictionary);
569
570 GenerateFastArrayLoad(
571 masm, receiver, key, scratch3, scratch2, scratch1, result, NULL, slow);
572 __ IncrementCounter(
573 isolate->counters()->keyed_load_generic_smi(), 1, scratch1, scratch2);
574 __ Ret();
575
576 __ Bind(&check_number_dictionary);
577 __ Ldr(scratch3, FieldMemOperand(receiver, JSObject::kElementsOffset));
578 __ Ldr(scratch2, FieldMemOperand(scratch3, JSObject::kMapOffset));
579
580 // Check whether we have a number dictionary.
581 __ JumpIfNotRoot(scratch2, Heap::kHashTableMapRootIndex, slow);
582
583 __ LoadFromNumberDictionary(
584 slow, scratch3, key, result, scratch1, scratch2, scratch4, scratch5);
585 __ Ret();
586 }
587
588 static void GenerateKeyedLoadWithNameKey(MacroAssembler* masm,
589 Register key,
590 Register receiver,
591 Register scratch1,
592 Register scratch2,
593 Register scratch3,
594 Register scratch4,
595 Register scratch5,
596 Label *slow) {
597 DCHECK(!AreAliased(
598 key, receiver, scratch1, scratch2, scratch3, scratch4, scratch5));
599
600 Isolate* isolate = masm->isolate();
601 Label probe_dictionary, property_array_property;
602 // If we can load the value, it should be returned in x0.
603 Register result = x0;
604
605 GenerateKeyedLoadReceiverCheck(
606 masm, receiver, scratch1, scratch2, Map::kHasNamedInterceptor, slow);
607
608 // If the receiver is a fast-case object, check the keyed lookup cache.
609 // Otherwise probe the dictionary.
610 __ Ldr(scratch2, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
611 __ Ldr(scratch3, FieldMemOperand(scratch2, HeapObject::kMapOffset));
612 __ JumpIfRoot(scratch3, Heap::kHashTableMapRootIndex, &probe_dictionary);
613
614 // We keep the map of the receiver in scratch1.
615 Register receiver_map = scratch1;
616
617 // Load the map of the receiver, compute the keyed lookup cache hash
618 // based on 32 bits of the map pointer and the name hash.
619 __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
620 __ Mov(scratch2, Operand(receiver_map, ASR, KeyedLookupCache::kMapHashShift));
621 __ Ldr(scratch3.W(), FieldMemOperand(key, Name::kHashFieldOffset));
622 __ Eor(scratch2, scratch2, Operand(scratch3, ASR, Name::kHashShift));
623 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
624 __ And(scratch2, scratch2, mask);
625
626 // Load the key (consisting of map and unique name) from the cache and
627 // check for match.
628 Label load_in_object_property;
629 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
630 Label hit_on_nth_entry[kEntriesPerBucket];
631 ExternalReference cache_keys =
632 ExternalReference::keyed_lookup_cache_keys(isolate);
633
634 __ Mov(scratch3, cache_keys);
635 __ Add(scratch3, scratch3, Operand(scratch2, LSL, kPointerSizeLog2 + 1));
636
637 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
638 Label try_next_entry;
639 // Load map and make scratch3 pointing to the next entry.
640 __ Ldr(scratch4, MemOperand(scratch3, kPointerSize * 2, PostIndex));
641 __ Cmp(receiver_map, scratch4);
642 __ B(ne, &try_next_entry);
643 __ Ldr(scratch4, MemOperand(scratch3, -kPointerSize)); // Load name
644 __ Cmp(key, scratch4);
645 __ B(eq, &hit_on_nth_entry[i]);
646 __ Bind(&try_next_entry);
647 }
648
649 // Last entry.
650 __ Ldr(scratch4, MemOperand(scratch3, kPointerSize, PostIndex));
651 __ Cmp(receiver_map, scratch4);
652 __ B(ne, slow);
653 __ Ldr(scratch4, MemOperand(scratch3));
654 __ Cmp(key, scratch4);
655 __ B(ne, slow);
656
657 // Get field offset.
658 ExternalReference cache_field_offsets =
659 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
660
661 // Hit on nth entry.
662 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
663 __ Bind(&hit_on_nth_entry[i]);
664 __ Mov(scratch3, cache_field_offsets);
665 if (i != 0) {
666 __ Add(scratch2, scratch2, i);
667 }
668 __ Ldr(scratch4.W(), MemOperand(scratch3, scratch2, LSL, 2));
669 __ Ldrb(scratch5,
670 FieldMemOperand(receiver_map, Map::kInObjectPropertiesOffset));
671 __ Subs(scratch4, scratch4, scratch5);
672 __ B(ge, &property_array_property);
673 if (i != 0) {
674 __ B(&load_in_object_property);
675 }
676 }
677
678 // Load in-object property.
679 __ Bind(&load_in_object_property);
680 __ Ldrb(scratch5, FieldMemOperand(receiver_map, Map::kInstanceSizeOffset));
681 __ Add(scratch5, scratch5, scratch4); // Index from start of object.
682 __ Sub(receiver, receiver, kHeapObjectTag); // Remove the heap tag.
683 __ Ldr(result, MemOperand(receiver, scratch5, LSL, kPointerSizeLog2));
684 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
685 1, scratch1, scratch2);
686 __ Ret();
687
688 // Load property array property.
689 __ Bind(&property_array_property);
690 __ Ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
691 __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
692 __ Ldr(result, MemOperand(scratch1, scratch4, LSL, kPointerSizeLog2));
693 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
694 1, scratch1, scratch2);
695 __ Ret();
696
697 // Do a quick inline probe of the receiver's dictionary, if it exists.
698 __ Bind(&probe_dictionary);
699 __ Ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
700 __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
701 GenerateGlobalInstanceTypeCheck(masm, scratch1, slow);
702 // Load the property.
703 GenerateDictionaryLoad(masm, slow, scratch2, key, result, scratch1, scratch3);
704 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
705 1, scratch1, scratch2);
706 __ Ret();
707 }
708
709
710 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
711 // The return address is in lr.
712 Label slow, check_name, index_smi, index_name;
713
714 Register key = NameRegister();
715 Register receiver = ReceiverRegister();
716 DCHECK(key.is(x2));
717 DCHECK(receiver.is(x1));
718
719 __ JumpIfNotSmi(key, &check_name);
720 __ Bind(&index_smi);
721 // Now the key is known to be a smi. This place is also jumped to from below
722 // where a numeric string is converted to a smi.
723 GenerateKeyedLoadWithSmiKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow);
724
725 // Slow case.
726 __ Bind(&slow);
727 __ IncrementCounter(
728 masm->isolate()->counters()->keyed_load_generic_slow(), 1, x4, x3);
729 GenerateRuntimeGetProperty(masm);
730
731 __ Bind(&check_name);
732 GenerateKeyNameCheck(masm, key, x0, x3, &index_name, &slow);
733
734 GenerateKeyedLoadWithNameKey(masm, key, receiver, x7, x3, x4, x5, x6, &slow);
735
736 __ Bind(&index_name);
737 __ IndexFromHash(x3, key);
738 // Now jump to the place where smi keys are handled.
739 __ B(&index_smi);
740 }
741
742
743 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
744 // Return address is in lr.
745 Label miss;
746
747 Register receiver = ReceiverRegister();
748 Register index = NameRegister();
749 Register result = x0;
750 Register scratch = x3;
751 DCHECK(!scratch.is(receiver) && !scratch.is(index));
752
753 StringCharAtGenerator char_at_generator(receiver,
754 index,
755 scratch,
756 result,
757 &miss, // When not a string.
758 &miss, // When not a number.
759 &miss, // When index out of range.
760 STRING_INDEX_IS_ARRAY_INDEX);
761 char_at_generator.GenerateFast(masm);
762 __ Ret();
763
764 StubRuntimeCallHelper call_helper;
765 char_at_generator.GenerateSlow(masm, call_helper);
766
767 __ Bind(&miss);
768 GenerateMiss(masm);
769 }
770
771
772 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
773 // Return address is in lr.
774 Label slow;
775
776 Register receiver = ReceiverRegister();
777 Register key = NameRegister();
778 Register scratch1 = x3;
779 Register scratch2 = x4;
780 DCHECK(!AreAliased(scratch1, scratch2, receiver, key));
781
782 // Check that the receiver isn't a smi.
783 __ JumpIfSmi(receiver, &slow);
784
785 // Check that the key is an array index, that is Uint32.
786 __ TestAndBranchIfAnySet(key, kSmiTagMask | kSmiSignMask, &slow);
787
788 // Get the map of the receiver.
789 Register map = scratch1;
790 __ Ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
791
792 // Check that it has indexed interceptor and access checks
793 // are not enabled for this object.
794 __ Ldrb(scratch2, FieldMemOperand(map, Map::kBitFieldOffset));
795 DCHECK(kSlowCaseBitFieldMask ==
796 ((1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor)));
797 __ Tbnz(scratch2, Map::kIsAccessCheckNeeded, &slow);
798 __ Tbz(scratch2, Map::kHasIndexedInterceptor, &slow);
799
800 // Everything is fine, call runtime.
801 __ Push(receiver, key);
802 __ TailCallExternalReference(
803 ExternalReference(IC_Utility(kLoadElementWithInterceptor),
804 masm->isolate()),
805 2, 1);
806
807 __ Bind(&slow);
808 GenerateMiss(masm);
809 }
810
811
812 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
813 ASM_LOCATION("KeyedStoreIC::GenerateMiss");
814
815 // Push receiver, key and value for runtime call.
816 __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
817
818 ExternalReference ref =
819 ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
820 __ TailCallExternalReference(ref, 3, 1);
821 }
822
823
824 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
825 ASM_LOCATION("KeyedStoreIC::GenerateSlow");
826
827 // Push receiver, key and value for runtime call.
828 __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
829
830 // The slow case calls into the runtime to complete the store without causing
831 // an IC miss that would otherwise cause a transition to the generic stub.
832 ExternalReference ref =
833 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
834 __ TailCallExternalReference(ref, 3, 1);
835 }
836
837
838 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
839 StrictMode strict_mode) {
840 ASM_LOCATION("KeyedStoreIC::GenerateRuntimeSetProperty");
841
842 // Push receiver, key and value for runtime call.
843 __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
844
845 // Push strict_mode for runtime call.
846 __ Mov(x10, Smi::FromInt(strict_mode));
847 __ Push(x10);
848
849 __ TailCallRuntime(Runtime::kSetProperty, 4, 1);
850 }
851
852
853 static void KeyedStoreGenerateGenericHelper(
854 MacroAssembler* masm,
855 Label* fast_object,
856 Label* fast_double,
857 Label* slow,
858 KeyedStoreCheckMap check_map,
859 KeyedStoreIncrementLength increment_length,
860 Register value,
861 Register key,
862 Register receiver,
863 Register receiver_map,
864 Register elements_map,
865 Register elements) {
866 DCHECK(!AreAliased(
867 value, key, receiver, receiver_map, elements_map, elements, x10, x11));
868
869 Label transition_smi_elements;
870 Label transition_double_elements;
871 Label fast_double_without_map_check;
872 Label non_double_value;
873 Label finish_store;
874
875 __ Bind(fast_object);
876 if (check_map == kCheckMap) {
877 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
878 __ Cmp(elements_map,
879 Operand(masm->isolate()->factory()->fixed_array_map()));
880 __ B(ne, fast_double);
881 }
882
883 // HOLECHECK: guards "A[i] = V"
884 // We have to go to the runtime if the current value is the hole because there
885 // may be a callback on the element.
886 Label holecheck_passed;
887 __ Add(x10, elements, FixedArray::kHeaderSize - kHeapObjectTag);
888 __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
889 __ Ldr(x11, MemOperand(x10));
890 __ JumpIfNotRoot(x11, Heap::kTheHoleValueRootIndex, &holecheck_passed);
891 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, x10, slow);
892 __ bind(&holecheck_passed);
893
894 // Smi stores don't require further checks.
895 __ JumpIfSmi(value, &finish_store);
896
897 // Escape to elements kind transition case.
898 __ CheckFastObjectElements(receiver_map, x10, &transition_smi_elements);
899
900 __ Bind(&finish_store);
901 if (increment_length == kIncrementLength) {
902 // Add 1 to receiver->length.
903 __ Add(x10, key, Smi::FromInt(1));
904 __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset));
905 }
906
907 Register address = x11;
908 __ Add(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
909 __ Add(address, address, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
910 __ Str(value, MemOperand(address));
911
912 Label dont_record_write;
913 __ JumpIfSmi(value, &dont_record_write);
914
915 // Update write barrier for the elements array address.
916 __ Mov(x10, value); // Preserve the value which is returned.
917 __ RecordWrite(elements,
918 address,
919 x10,
920 kLRHasNotBeenSaved,
921 kDontSaveFPRegs,
922 EMIT_REMEMBERED_SET,
923 OMIT_SMI_CHECK);
924
925 __ Bind(&dont_record_write);
926 __ Ret();
927
928
929 __ Bind(fast_double);
930 if (check_map == kCheckMap) {
931 // Check for fast double array case. If this fails, call through to the
932 // runtime.
933 __ JumpIfNotRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex, slow);
934 }
935
936 // HOLECHECK: guards "A[i] double hole?"
937 // We have to see if the double version of the hole is present. If so go to
938 // the runtime.
939 __ Add(x10, elements, FixedDoubleArray::kHeaderSize - kHeapObjectTag);
940 __ Add(x10, x10, Operand::UntagSmiAndScale(key, kPointerSizeLog2));
941 __ Ldr(x11, MemOperand(x10));
942 __ CompareAndBranch(x11, kHoleNanInt64, ne, &fast_double_without_map_check);
943 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, x10, slow);
944
945 __ Bind(&fast_double_without_map_check);
946 __ StoreNumberToDoubleElements(value,
947 key,
948 elements,
949 x10,
950 d0,
951 &transition_double_elements);
952 if (increment_length == kIncrementLength) {
953 // Add 1 to receiver->length.
954 __ Add(x10, key, Smi::FromInt(1));
955 __ Str(x10, FieldMemOperand(receiver, JSArray::kLengthOffset));
956 }
957 __ Ret();
958
959
960 __ Bind(&transition_smi_elements);
961 // Transition the array appropriately depending on the value type.
962 __ Ldr(x10, FieldMemOperand(value, HeapObject::kMapOffset));
963 __ JumpIfNotRoot(x10, Heap::kHeapNumberMapRootIndex, &non_double_value);
964
965 // Value is a double. Transition FAST_SMI_ELEMENTS ->
966 // FAST_DOUBLE_ELEMENTS and complete the store.
967 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
968 FAST_DOUBLE_ELEMENTS,
969 receiver_map,
970 x10,
971 x11,
972 slow);
973 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
974 FAST_DOUBLE_ELEMENTS);
975 ElementsTransitionGenerator::GenerateSmiToDouble(
976 masm, receiver, key, value, receiver_map, mode, slow);
977 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
978 __ B(&fast_double_without_map_check);
979
980 __ Bind(&non_double_value);
981 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS.
982 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
983 FAST_ELEMENTS,
984 receiver_map,
985 x10,
986 x11,
987 slow);
988
989 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
990 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
991 masm, receiver, key, value, receiver_map, mode, slow);
992
993 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
994 __ B(&finish_store);
995
996 __ Bind(&transition_double_elements);
997 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
998 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
999 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1000 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1001 FAST_ELEMENTS,
1002 receiver_map,
1003 x10,
1004 x11,
1005 slow);
1006 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
1007 ElementsTransitionGenerator::GenerateDoubleToObject(
1008 masm, receiver, key, value, receiver_map, mode, slow);
1009 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1010 __ B(&finish_store);
1011 }
1012
1013
1014 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1015 StrictMode strict_mode) {
1016 ASM_LOCATION("KeyedStoreIC::GenerateGeneric");
1017 Label slow;
1018 Label array;
1019 Label fast_object;
1020 Label extra;
1021 Label fast_object_grow;
1022 Label fast_double_grow;
1023 Label fast_double;
1024
1025 Register value = ValueRegister();
1026 Register key = NameRegister();
1027 Register receiver = ReceiverRegister();
1028 DCHECK(receiver.is(x1));
1029 DCHECK(key.is(x2));
1030 DCHECK(value.is(x0));
1031
1032 Register receiver_map = x3;
1033 Register elements = x4;
1034 Register elements_map = x5;
1035
1036 __ JumpIfNotSmi(key, &slow);
1037 __ JumpIfSmi(receiver, &slow);
1038 __ Ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1039
1040 // Check that the receiver does not require access checks and is not observed.
1041 // The generic stub does not perform map checks or handle observed objects.
1042 __ Ldrb(x10, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
1043 __ TestAndBranchIfAnySet(
1044 x10, (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kIsObserved), &slow);
1045
1046 // Check if the object is a JS array or not.
1047 Register instance_type = x10;
1048 __ CompareInstanceType(receiver_map, instance_type, JS_ARRAY_TYPE);
1049 __ B(eq, &array);
1050 // Check that the object is some kind of JSObject.
1051 __ Cmp(instance_type, FIRST_JS_OBJECT_TYPE);
1052 __ B(lt, &slow);
1053
1054 // Object case: Check key against length in the elements array.
1055 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1056 // Check array bounds. Both the key and the length of FixedArray are smis.
1057 __ Ldrsw(x10, UntagSmiFieldMemOperand(elements, FixedArray::kLengthOffset));
1058 __ Cmp(x10, Operand::UntagSmi(key));
1059 __ B(hi, &fast_object);
1060
1061
1062 __ Bind(&slow);
1063 // Slow case, handle jump to runtime.
1064 // Live values:
1065 // x0: value
1066 // x1: key
1067 // x2: receiver
1068 GenerateRuntimeSetProperty(masm, strict_mode);
1069
1070
1071 __ Bind(&extra);
1072 // Extra capacity case: Check if there is extra capacity to
1073 // perform the store and update the length. Used for adding one
1074 // element to the array by writing to array[array.length].
1075
1076 // Check for room in the elements backing store.
1077 // Both the key and the length of FixedArray are smis.
1078 __ Ldrsw(x10, UntagSmiFieldMemOperand(elements, FixedArray::kLengthOffset));
1079 __ Cmp(x10, Operand::UntagSmi(key));
1080 __ B(ls, &slow);
1081
1082 __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1083 __ Cmp(elements_map, Operand(masm->isolate()->factory()->fixed_array_map()));
1084 __ B(eq, &fast_object_grow);
1085 __ Cmp(elements_map,
1086 Operand(masm->isolate()->factory()->fixed_double_array_map()));
1087 __ B(eq, &fast_double_grow);
1088 __ B(&slow);
1089
1090
1091 __ Bind(&array);
1092 // Array case: Get the length and the elements array from the JS
1093 // array. Check that the array is in fast mode (and writable); if it
1094 // is the length is always a smi.
1095
1096 __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1097
1098 // Check the key against the length in the array.
1099 __ Ldrsw(x10, UntagSmiFieldMemOperand(receiver, JSArray::kLengthOffset));
1100 __ Cmp(x10, Operand::UntagSmi(key));
1101 __ B(eq, &extra); // We can handle the case where we are appending 1 element.
1102 __ B(lo, &slow);
1103
1104 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
1105 &slow, kCheckMap, kDontIncrementLength,
1106 value, key, receiver, receiver_map,
1107 elements_map, elements);
1108 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
1109 &slow, kDontCheckMap, kIncrementLength,
1110 value, key, receiver, receiver_map,
1111 elements_map, elements);
1112 }
1113
1114
1115 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1116 Register receiver = ReceiverRegister();
1117 Register name = NameRegister();
1118 DCHECK(!AreAliased(receiver, name, ValueRegister(), x3, x4, x5, x6));
1119
1120 // Probe the stub cache.
1121 Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
1122 Code::ComputeHandlerFlags(Code::STORE_IC));
1123 masm->isolate()->stub_cache()->GenerateProbe(
1124 masm, flags, receiver, name, x3, x4, x5, x6);
1125
1126 // Cache miss: Jump to runtime.
1127 GenerateMiss(masm);
1128 }
1129
1130
1131 void StoreIC::GenerateMiss(MacroAssembler* masm) {
1132 __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
1133
1134 // Tail call to the entry.
1135 ExternalReference ref =
1136 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1137 __ TailCallExternalReference(ref, 3, 1);
1138 }
1139
1140
1141 void StoreIC::GenerateNormal(MacroAssembler* masm) {
1142 Label miss;
1143 Register value = ValueRegister();
1144 Register receiver = ReceiverRegister();
1145 Register name = NameRegister();
1146 Register dictionary = x3;
1147 DCHECK(!AreAliased(value, receiver, name, x3, x4, x5));
1148
1149 __ Ldr(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
1150
1151 GenerateDictionaryStore(masm, &miss, dictionary, name, value, x4, x5);
1152 Counters* counters = masm->isolate()->counters();
1153 __ IncrementCounter(counters->store_normal_hit(), 1, x4, x5);
1154 __ Ret();
1155
1156 // Cache miss: Jump to runtime.
1157 __ Bind(&miss);
1158 __ IncrementCounter(counters->store_normal_miss(), 1, x4, x5);
1159 GenerateMiss(masm);
1160 }
1161
1162
1163 void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1164 StrictMode strict_mode) {
1165 ASM_LOCATION("StoreIC::GenerateRuntimeSetProperty");
1166
1167 __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
1168
1169 __ Mov(x10, Smi::FromInt(strict_mode));
1170 __ Push(x10);
1171
1172 // Do tail-call to runtime routine.
1173 __ TailCallRuntime(Runtime::kSetProperty, 4, 1);
1174 }
1175
1176
1177 void StoreIC::GenerateSlow(MacroAssembler* masm) {
1178 // ---------- S t a t e --------------
1179 // -- x0 : value
1180 // -- x1 : receiver
1181 // -- x2 : name
1182 // -- lr : return address
1183 // -----------------------------------
1184
1185 // Push receiver, name and value for runtime call.
1186 __ Push(ReceiverRegister(), NameRegister(), ValueRegister());
1187
1188 // The slow case calls into the runtime to complete the store without causing
1189 // an IC miss that would otherwise cause a transition to the generic stub.
1190 ExternalReference ref =
1191 ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate());
1192 __ TailCallExternalReference(ref, 3, 1);
1193 }
1194
1195
1196 Condition CompareIC::ComputeCondition(Token::Value op) {
1197 switch (op) {
1198 case Token::EQ_STRICT:
1199 case Token::EQ:
1200 return eq;
1201 case Token::LT:
1202 return lt;
1203 case Token::GT:
1204 return gt;
1205 case Token::LTE:
1206 return le;
1207 case Token::GTE:
1208 return ge;
1209 default:
1210 UNREACHABLE();
1211 return al;
1212 }
1213 }
1214
1215
1216 bool CompareIC::HasInlinedSmiCode(Address address) {
1217 // The address of the instruction following the call.
1218 Address info_address =
1219 Assembler::return_address_from_call_start(address);
1220
1221 InstructionSequence* patch_info = InstructionSequence::At(info_address);
1222 return patch_info->IsInlineData();
1223 }
1224
1225
1226 // Activate a SMI fast-path by patching the instructions generated by
1227 // JumpPatchSite::EmitJumpIf(Not)Smi(), using the information encoded by
1228 // JumpPatchSite::EmitPatchInfo().
1229 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
1230 // The patch information is encoded in the instruction stream using
1231 // instructions which have no side effects, so we can safely execute them.
1232 // The patch information is encoded directly after the call to the helper
1233 // function which is requesting this patch operation.
1234 Address info_address =
1235 Assembler::return_address_from_call_start(address);
1236 InlineSmiCheckInfo info(info_address);
1237
1238 // Check and decode the patch information instruction.
1239 if (!info.HasSmiCheck()) {
1240 return;
1241 }
1242
1243 if (FLAG_trace_ic) {
1244 PrintF("[ Patching ic at %p, marker=%p, SMI check=%p\n",
1245 address, info_address, reinterpret_cast<void*>(info.SmiCheck()));
1246 }
1247
1248 // Patch and activate code generated by JumpPatchSite::EmitJumpIfNotSmi()
1249 // and JumpPatchSite::EmitJumpIfSmi().
1250 // Changing
1251 // tb(n)z xzr, #0, <target>
1252 // to
1253 // tb(!n)z test_reg, #0, <target>
1254 Instruction* to_patch = info.SmiCheck();
1255 PatchingAssembler patcher(to_patch, 1);
1256 DCHECK(to_patch->IsTestBranch());
1257 DCHECK(to_patch->ImmTestBranchBit5() == 0);
1258 DCHECK(to_patch->ImmTestBranchBit40() == 0);
1259
1260 STATIC_ASSERT(kSmiTag == 0);
1261 STATIC_ASSERT(kSmiTagMask == 1);
1262
1263 int branch_imm = to_patch->ImmTestBranch();
1264 Register smi_reg;
1265 if (check == ENABLE_INLINED_SMI_CHECK) {
1266 DCHECK(to_patch->Rt() == xzr.code());
1267 smi_reg = info.SmiRegister();
1268 } else {
1269 DCHECK(check == DISABLE_INLINED_SMI_CHECK);
1270 DCHECK(to_patch->Rt() != xzr.code());
1271 smi_reg = xzr;
1272 }
1273
1274 if (to_patch->Mask(TestBranchMask) == TBZ) {
1275 // This is JumpIfNotSmi(smi_reg, branch_imm).
1276 patcher.tbnz(smi_reg, 0, branch_imm);
1277 } else {
1278 DCHECK(to_patch->Mask(TestBranchMask) == TBNZ);
1279 // This is JumpIfSmi(smi_reg, branch_imm).
1280 patcher.tbz(smi_reg, 0, branch_imm);
1281 }
1282 }
1283
1284
1285 } } // namespace v8::internal
1286
1287 #endif // V8_TARGET_ARCH_ARM64
OLDNEW
« no previous file with comments | « src/arm64/full-codegen-arm64.cc ('k') | src/arm64/lithium-codegen-arm64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698