48
48
#define __ ACCESS_MASM(masm)
50
// Helper function used from LoadIC/CallIC GenerateNormal.
51
static void GenerateDictionaryLoad(MacroAssembler* masm,
57
// t0 - used to hold the property dictionary.
59
// t1 - initially the receiver
60
// - used for the index into the property dictionary
61
// - holds the result on exit.
63
// r3 - used as temporary and to hold the capacity of the property
66
// r2 - holds the name of the property and is unchanged.
67
// r4 - used as temporary.
71
// Check for the absence of an interceptor.
72
// Load the map into t0.
73
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset));
75
// Bail out if the receiver has a named interceptor.
76
__ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset));
77
__ tst(r3, Operand(1 << Map::kHasNamedInterceptor));
51
static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
53
Label* global_object) {
55
// type: holds the receiver instance type on entry.
56
__ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
57
__ b(eq, global_object);
58
__ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
59
__ b(eq, global_object);
60
__ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
61
__ b(eq, global_object);
65
// Generated code falls through if the receiver is a regular non-global
66
// JS object with slow properties and no interceptors.
67
static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
74
// receiver: holds the receiver on entry and is unchanged.
75
// elements: holds the property dictionary on fall through.
77
// t0: used to holds the receiver map.
78
// t1: used to holds the receiver instance type, receiver bit mask and
81
// Check that the receiver isn't a smi.
82
__ tst(receiver, Operand(kSmiTagMask));
85
// Check that the receiver is a valid JS object.
86
__ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
89
// If this assert fails, we have to check upper bound too.
90
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
92
GenerateGlobalInstanceTypeCheck(masm, t1, miss);
94
// Check that the global object does not require access checks.
95
__ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
96
__ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
97
(1 << Map::kHasNamedInterceptor)));
80
// Bail out if we have a JS global proxy object.
81
__ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset));
82
__ cmp(r3, Operand(JS_GLOBAL_PROXY_TYPE));
85
// Possible work-around for http://crbug.com/16276.
86
// See also: http://codereview.chromium.org/155418.
87
__ cmp(r3, Operand(JS_GLOBAL_OBJECT_TYPE));
89
__ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
92
// Check that the properties array is a dictionary.
93
__ ldr(t0, FieldMemOperand(t1, JSObject::kPropertiesOffset));
94
__ ldr(r3, FieldMemOperand(t0, HeapObject::kMapOffset));
100
__ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
101
__ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
95
102
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
108
// Probe the string dictionary in the |elements| register. Jump to the
109
// |done| label if a property with the given name is found. Jump to
110
// the |miss| label otherwise.
111
static void GenerateStringDictionaryProbes(MacroAssembler* masm,
99
118
// Compute the capacity mask.
100
119
const int kCapacityOffset = StringDictionary::kHeaderSize +
101
120
StringDictionary::kCapacityIndex * kPointerSize;
102
__ ldr(r3, FieldMemOperand(t0, kCapacityOffset));
103
__ mov(r3, Operand(r3, ASR, kSmiTagSize)); // convert smi to int
104
__ sub(r3, r3, Operand(1));
121
__ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
122
__ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int
123
__ sub(scratch1, scratch1, Operand(1));
106
125
const int kElementsStartOffset = StringDictionary::kHeaderSize +
107
126
StringDictionary::kElementsStartIndex * kPointerSize;
112
131
static const int kProbes = 4;
113
132
for (int i = 0; i < kProbes; i++) {
114
133
// Compute the masked index: (hash + i + i * i) & mask.
115
__ ldr(r4, FieldMemOperand(r2, String::kHashFieldOffset));
134
__ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
117
136
// Add the probe offset (i + i * i) left shifted to avoid right shifting
118
137
// the hash in a separate instruction. The value hash + i + i * i is right
119
138
// shifted in the following and instruction.
120
139
ASSERT(StringDictionary::GetProbeOffset(i) <
121
140
1 << (32 - String::kHashFieldOffset));
122
__ add(r4, r4, Operand(
141
__ add(scratch2, scratch2, Operand(
123
142
StringDictionary::GetProbeOffset(i) << String::kHashShift));
125
__ and_(r4, r3, Operand(r4, LSR, String::kHashShift));
144
__ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
127
146
// Scale the index by multiplying by the element size.
128
147
ASSERT(StringDictionary::kEntrySize == 3);
129
__ add(r4, r4, Operand(r4, LSL, 1)); // r4 = r4 * 3
148
// scratch2 = scratch2 * 3.
149
__ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
131
151
// Check if the key is identical to the name.
132
__ add(r4, t0, Operand(r4, LSL, 2));
133
__ ldr(ip, FieldMemOperand(r4, kElementsStartOffset));
134
__ cmp(r2, Operand(ip));
152
__ add(scratch2, elements, Operand(scratch2, LSL, 2));
153
__ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
154
__ cmp(name, Operand(ip));
135
155
if (i != kProbes - 1) {
142
// Check that the value is a normal property.
143
__ bind(&done); // r4 == t0 + 4*index
144
__ ldr(r3, FieldMemOperand(r4, kElementsStartOffset + 2 * kPointerSize));
145
__ tst(r3, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
164
// Helper function used from LoadIC/CallIC GenerateNormal.
166
// elements: Property dictionary. It is not clobbered if a jump to the miss
168
// name: Property name. It is not clobbered if a jump to the miss label is
170
// result: Register for the result. It is only updated if a jump to the miss
171
// label is not done. Can be the same as elements or name clobbering
172
// one of these in the case of not jumping to the miss label.
173
// The two scratch registers need to be different from elements, name and
175
// The generated code assumes that the receiver has slow properties,
176
// is not a global object and does not have interceptors.
177
static void GenerateDictionaryLoad(MacroAssembler* masm,
184
// Main use of the scratch registers.
185
// scratch1: Used as temporary and to hold the capacity of the property
187
// scratch2: Used as temporary.
190
// Probe the dictionary.
191
GenerateStringDictionaryProbes(masm,
199
// If probing finds an entry check that the value is a normal
201
__ bind(&done); // scratch2 == elements + 4 * index
202
const int kElementsStartOffset = StringDictionary::kHeaderSize +
203
StringDictionary::kElementsStartIndex * kPointerSize;
204
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
205
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
206
__ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
148
209
// Get the value at the masked, scaled index and return.
149
__ ldr(t1, FieldMemOperand(r4, kElementsStartOffset + 1 * kPointerSize));
211
FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
215
// Helper function used from StoreIC::GenerateNormal.
217
// elements: Property dictionary. It is not clobbered if a jump to the miss
219
// name: Property name. It is not clobbered if a jump to the miss label is
221
// value: The value to store.
222
// The two scratch registers need to be different from elements, name and
224
// The generated code assumes that the receiver has slow properties,
225
// is not a global object and does not have interceptors.
226
static void GenerateDictionaryStore(MacroAssembler* masm,
233
// Main use of the scratch registers.
234
// scratch1: Used as temporary and to hold the capacity of the property
236
// scratch2: Used as temporary.
239
// Probe the dictionary.
240
GenerateStringDictionaryProbes(masm,
248
// If probing finds an entry in the dictionary check that the value
249
// is a normal property that is not read only.
250
__ bind(&done); // scratch2 == elements + 4 * index
251
const int kElementsStartOffset = StringDictionary::kHeaderSize +
252
StringDictionary::kElementsStartIndex * kPointerSize;
253
const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
254
const int kTypeAndReadOnlyMask
255
= (PropertyDetails::TypeField::mask() |
256
PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
257
__ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
258
__ tst(scratch1, Operand(kTypeAndReadOnlyMask));
261
// Store the value at the masked, scaled index and return.
262
const int kValueOffset = kElementsStartOffset + kPointerSize;
263
__ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
264
__ str(value, MemOperand(scratch2));
266
// Update the write barrier. Make sure not to clobber the value.
267
__ mov(scratch1, value);
268
__ RecordWrite(elements, scratch2, scratch1);
413
// Checks the receiver for special cases (value type, slow case bits).
414
// Falls through for regular JS object.
415
static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
421
// Check that the object isn't a smi.
422
__ BranchOnSmi(receiver, slow);
423
// Get the map of the receiver.
424
__ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
426
__ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
428
Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
430
// Check that the object is some kind of JS object EXCEPT JS Value type.
431
// In the case that the object is a value-wrapper object,
432
// we enter the runtime system to make sure that indexing into string
433
// objects work as intended.
434
ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
435
__ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
436
__ cmp(scratch1, Operand(JS_OBJECT_TYPE));
441
// Loads an indexed element from a fast case array.
442
static void GenerateFastArrayLoad(MacroAssembler* masm,
449
Label* not_fast_array,
450
Label* out_of_range) {
453
// receiver - holds the receiver on entry.
454
// Unchanged unless 'result' is the same register.
456
// key - holds the smi key on entry.
457
// Unchanged unless 'result' is the same register.
459
// elements - holds the elements of the receiver on exit.
461
// result - holds the result on exit if the load succeeded.
462
// Allowed to be the the same as 'receiver' or 'key'.
463
// Unchanged on bailout so 'receiver' and 'key' can be safely
464
// used by further computation.
466
// Scratch registers:
468
// scratch1 - used to hold elements map and elements length.
469
// Holds the elements map if not_fast_array branch is taken.
471
// scratch2 - used to hold the loaded value.
473
__ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
474
// Check that the object is in fast mode (not dictionary).
475
__ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
476
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
477
__ cmp(scratch1, ip);
478
__ b(ne, not_fast_array);
479
// Check that the key (index) is within bounds.
480
__ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
481
__ cmp(key, Operand(scratch1));
482
__ b(hs, out_of_range);
483
// Fast case: Do the load.
484
__ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
486
ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
488
MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
489
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
490
__ cmp(scratch2, ip);
491
// In case the loaded value is the_hole we have to consult GetProperty
492
// to ensure the prototype chain is searched.
493
__ b(eq, out_of_range);
494
__ mov(result, scratch2);
498
// Checks whether a key is an array index string or a symbol string.
499
// Falls through if a key is a symbol.
500
static void GenerateKeyStringCheck(MacroAssembler* masm,
506
// The key is not a smi.
508
__ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
509
__ b(ge, not_symbol);
511
// Is the string an array index, with cached numeric value?
512
__ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
513
__ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
514
__ b(eq, index_string);
516
// Is the string a symbol?
518
__ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
519
ASSERT(kSymbolTag != 0);
520
__ tst(hash, Operand(kIsSymbolMask));
521
__ b(eq, not_symbol);
525
// Picks out an array index from the hash field.
526
static void GenerateIndexFromHash(MacroAssembler* masm,
530
// key - holds the overwritten key on exit.
531
// hash - holds the key's hash. Clobbered.
533
// If the hash field contains an array index pick it out. The assert checks
534
// that the constants for the maximum number of digits for an array index
535
// cached in the hash field and the number of bits reserved for it does not
537
ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
538
(1 << String::kArrayIndexValueBits));
539
// We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
540
// the low kHashShift bits.
541
ASSERT(String::kHashShift >= kSmiTagSize);
542
// Here we actually clobber the key which will be used if calling into
543
// runtime later. However as the new key is the numeric value of a string key
544
// there is no difference in using either key.
545
ASSERT(String::kHashShift >= kSmiTagSize);
546
__ Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
547
__ mov(key, Operand(hash, LSL, kSmiTagSize));
288
551
// Defined in ic.cc.
289
552
Object* CallIC_Miss(Arguments args);
291
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
554
// The generated code does not accept smi keys.
555
// The generated code falls through if both probes miss.
556
static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
292
559
// ----------- S t a t e -------------
294
// -- lr : return address
295
562
// -----------------------------------
296
563
Label number, non_number, non_string, boolean, probe, miss;
298
// Get the receiver of the function from the stack into r1.
299
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
301
565
// Probe the stub cache.
302
566
Code::Flags flags =
303
Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
567
Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
304
568
StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
306
570
// If the stub cache probing failed, the receiver might be a value.
364
624
__ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
367
// Patch the receiver with the global proxy if necessary.
368
if (is_global_object) {
369
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
370
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
371
__ str(r0, MemOperand(sp, argc * kPointerSize));
374
627
// Invoke the function.
375
628
ParameterCount actual(argc);
376
629
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
380
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
633
static void GenerateCallNormal(MacroAssembler* masm, int argc) {
381
634
// ----------- S t a t e -------------
383
636
// -- lr : return address
384
637
// -----------------------------------
385
Label miss, global_object, non_global_object;
387
640
// Get the receiver of the function from the stack into r1.
388
641
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
390
// Check that the receiver isn't a smi.
391
__ tst(r1, Operand(kSmiTagMask));
394
// Check that the receiver is a valid JS object. Put the map in r3.
395
__ CompareObjectType(r1, r3, r0, FIRST_JS_OBJECT_TYPE);
398
// If this assert fails, we have to check upper bound too.
399
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
401
// Check for access to global object.
402
__ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
403
__ b(eq, &global_object);
404
__ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
405
__ b(ne, &non_global_object);
407
// Accessing global object: Load and invoke.
408
__ bind(&global_object);
409
// Check that the global object does not require access checks.
410
__ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
411
__ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
413
GenerateNormalHelper(masm, argc, true, &miss, r4);
415
// Accessing non-global object: Check for access to global proxy.
416
Label global_proxy, invoke;
417
__ bind(&non_global_object);
418
__ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
419
__ b(eq, &global_proxy);
420
// Check that the non-global, non-global-proxy object does not
421
// require access checks.
422
__ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
423
__ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
426
GenerateNormalHelper(masm, argc, false, &miss, r4);
428
// Global object access: Check access rights.
429
__ bind(&global_proxy);
430
__ CheckAccessGlobalProxy(r1, r0, &miss);
433
// Cache miss: Jump to runtime.
643
GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
646
// Search the dictionary - put result in register r1.
647
GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
649
GenerateFunctionTailCall(masm, argc, &miss, r4);
435
GenerateMiss(masm, argc);
439
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
655
static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
440
656
// ----------- S t a t e -------------
442
658
// -- lr : return address
443
659
// -----------------------------------
661
if (id == IC::kCallIC_Miss) {
662
__ IncrementCounter(&Counters::call_miss, 1, r3, r4);
664
__ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
445
667
// Get the receiver of the function from the stack.
446
668
__ ldr(r3, MemOperand(sp, argc * kPointerSize));
462
684
__ LeaveInternalFrame();
464
686
// Check if the receiver is a global object of some sort.
465
Label invoke, global;
466
__ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
467
__ tst(r2, Operand(kSmiTagMask));
469
__ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
471
__ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
687
// This can happen only for regular CallIC but not KeyedCallIC.
688
if (id == IC::kCallIC_Miss) {
689
Label invoke, global;
690
__ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
691
__ tst(r2, Operand(kSmiTagMask));
693
__ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
695
__ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
474
// Patch the receiver on the stack.
476
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
477
__ str(r2, MemOperand(sp, argc * kPointerSize));
698
// Patch the receiver on the stack.
700
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
701
__ str(r2, MemOperand(sp, argc * kPointerSize));
479
705
// Invoke the function.
480
706
ParameterCount actual(argc);
482
707
__ InvokeFunction(r1, actual, JUMP_FUNCTION);
711
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
712
// ----------- S t a t e -------------
714
// -- lr : return address
715
// -----------------------------------
717
GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
721
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
722
// ----------- S t a t e -------------
724
// -- lr : return address
725
// -----------------------------------
727
// Get the receiver of the function from the stack into r1.
728
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
729
GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
730
GenerateMiss(masm, argc);
734
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
735
// ----------- S t a t e -------------
737
// -- lr : return address
738
// -----------------------------------
740
GenerateCallNormal(masm, argc);
741
GenerateMiss(masm, argc);
745
void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
746
// ----------- S t a t e -------------
748
// -- lr : return address
749
// -----------------------------------
751
GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
755
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
756
// ----------- S t a t e -------------
758
// -- lr : return address
759
// -----------------------------------
761
// Get the receiver of the function from the stack into r1.
762
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
764
Label do_call, slow_call, slow_load, slow_reload_receiver;
765
Label check_number_dictionary, check_string, lookup_monomorphic_cache;
766
Label index_smi, index_string;
768
// Check that the key is a smi.
769
__ BranchOnNotSmi(r2, &check_string);
771
// Now the key is known to be a smi. This place is also jumped to from below
772
// where a numeric string is converted to a smi.
774
GenerateKeyedLoadReceiverCheck(
775
masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
777
GenerateFastArrayLoad(
778
masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
779
__ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
782
// receiver in r1 is not used after this point.
785
GenerateFunctionTailCall(masm, argc, &slow_call, r0);
787
__ bind(&check_number_dictionary);
791
// Check whether the elements is a number dictionary.
792
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
794
__ b(ne, &slow_load);
795
__ mov(r0, Operand(r2, ASR, kSmiTagSize));
796
// r0: untagged index
797
GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
798
__ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
802
// This branch is taken when calling KeyedCallIC_Miss is neither required
804
__ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
805
__ EnterInternalFrame();
806
__ push(r2); // save the key
807
__ Push(r1, r2); // pass the receiver and the key
808
__ CallRuntime(Runtime::kKeyedGetProperty, 2);
809
__ pop(r2); // restore the key
810
__ LeaveInternalFrame();
814
__ bind(&check_string);
815
GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
817
// The key is known to be a symbol.
818
// If the receiver is a regular JS object with slow properties then do
819
// a quick inline probe of the receiver's dictionary.
820
// Otherwise do the monomorphic cache probe.
821
GenerateKeyedLoadReceiverCheck(
822
masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
824
__ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
825
__ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
826
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
828
__ b(ne, &lookup_monomorphic_cache);
830
GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
831
__ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
834
__ bind(&lookup_monomorphic_cache);
835
__ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
836
GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
837
// Fall through on miss.
840
// This branch is taken if:
841
// - the receiver requires boxing or access check,
842
// - the key is neither smi nor symbol,
843
// - the value loaded is not a function,
844
// - there is hope that the runtime will create a monomorphic call stub
845
// that will get fetched next time.
846
__ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
847
GenerateMiss(masm, argc);
849
__ bind(&index_string);
850
GenerateIndexFromHash(masm, r2, r3);
851
// Now jump to the place where smi keys are handled.
856
void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
857
// ----------- S t a t e -------------
859
// -- lr : return address
860
// -----------------------------------
862
GenerateCallNormal(masm, argc);
863
GenerateMiss(masm, argc);
486
867
// Defined in ic.cc.
487
868
Object* LoadIC_Miss(Arguments args);
512
893
// -- r0 : receiver
513
894
// -- sp[0] : receiver
514
895
// -----------------------------------
515
Label miss, probe, global;
517
// Check that the receiver isn't a smi.
518
__ tst(r0, Operand(kSmiTagMask));
521
// Check that the receiver is a valid JS object. Put the map in r3.
522
__ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE);
524
// If this assert fails, we have to check upper bound too.
525
ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
527
// Check for access to global object (unlikely).
528
__ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
531
// Check for non-global object that requires access check.
532
__ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
533
__ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
537
GenerateDictionaryLoad(masm, &miss, r1, r0);
898
GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
901
GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
540
// Global object access: Check access rights.
542
__ CheckAccessGlobalProxy(r0, r1, &miss);
545
// Cache miss: Restore receiver from stack and jump to runtime.
904
// Cache miss: Jump to runtime.
547
906
GenerateMiss(masm);
632
void KeyedLoadIC::ClearInlinedVersion(Address address) {
633
// Reset the map check of the inlined keyed load (if present) to
634
// guarantee failure by holding an invalid map (the null value).
635
PatchInlinedLoad(address, Heap::null_value());
991
bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
992
// Find the end of the inlined code for the store if there is an
993
// inlined version of the store.
994
Address inline_end_address;
995
if (!IsInlinedICSite(address, &inline_end_address)) return false;
997
// Compute the address of the map load instruction.
998
Address ldr_map_instr_address =
1000
(CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
1001
Assembler::kInstrSize);
1003
// Update the offsets if initializing the inlined store. No reason
1004
// to update the offsets when clearing the inlined version because
1005
// it will bail out in the map check.
1006
if (map != Heap::null_value()) {
1007
// Patch the offset in the actual store instruction.
1008
Address str_property_instr_address =
1009
ldr_map_instr_address + 3 * Assembler::kInstrSize;
1010
Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
1011
ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
1012
str_property_instr = Assembler::SetStrRegisterImmediateOffset(
1013
str_property_instr, offset - kHeapObjectTag);
1014
Assembler::instr_at_put(str_property_instr_address, str_property_instr);
1016
// Patch the offset in the add instruction that is part of the
1018
Address add_offset_instr_address =
1019
str_property_instr_address + Assembler::kInstrSize;
1020
Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
1021
ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
1022
add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
1023
add_offset_instr, offset - kHeapObjectTag);
1024
Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
1026
// Indicate that code has changed.
1027
CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
1030
// Patch the map check.
1031
Assembler::set_target_address_at(ldr_map_instr_address,
1032
reinterpret_cast<Address>(map));
720
1106
// -- r1 : receiver
721
1107
// -----------------------------------
722
Label slow, fast, check_pixel_array, check_number_dictionary;
1108
Label slow, check_string, index_smi, index_string, property_array_property;
1109
Label check_pixel_array, probe_dictionary, check_number_dictionary;
724
1111
Register key = r0;
725
1112
Register receiver = r1;
727
// Check that the object isn't a smi.
728
__ BranchOnSmi(receiver, &slow);
729
// Get the map of the receiver.
730
__ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
732
__ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
733
__ tst(r3, Operand(kSlowCaseBitFieldMask));
735
// Check that the object is some kind of JS object EXCEPT JS Value type.
736
// In the case that the object is a value-wrapper object,
737
// we enter the runtime system to make sure that indexing into string
738
// objects work as intended.
739
ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
740
__ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
741
__ cmp(r2, Operand(JS_OBJECT_TYPE));
744
1114
// Check that the key is a smi.
745
__ BranchOnNotSmi(key, &slow);
746
// Untag key into r2..
747
__ mov(r2, Operand(key, ASR, kSmiTagSize));
749
// Get the elements array of the object.
750
__ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
751
// Check that the object is in fast mode (not dictionary).
752
__ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
753
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
755
__ b(ne, &check_pixel_array);
756
// Check that the key (index) is within bounds.
757
__ ldr(r3, FieldMemOperand(r4, Array::kLengthOffset));
760
// Fast case: Do the load.
761
__ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
762
__ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2));
763
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
765
// In case the loaded value is the_hole we have to consult GetProperty
766
// to ensure the prototype chain is searched.
1115
__ BranchOnNotSmi(key, &check_string);
1116
__ bind(&index_smi);
1117
// Now the key is known to be a smi. This place is also jumped to from below
1118
// where a numeric string is converted to a smi.
1120
GenerateKeyedLoadReceiverCheck(
1121
masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
1123
GenerateFastArrayLoad(
1124
masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow);
1125
__ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
771
1128
// Check whether the elements is a pixel array.
773
// r2: untagged index
774
1130
// r3: elements map
776
1132
__ bind(&check_pixel_array);
788
1145
__ bind(&check_number_dictionary);
789
1146
// Check whether the elements is a number dictionary.
791
// r2: untagged index
792
1148
// r3: elements map
794
1150
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
796
1152
__ b(ne, &slow);
797
GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5);
1153
__ mov(r2, Operand(r0, ASR, kSmiTagSize));
1154
GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
801
1157
// Slow case, key and receiver still in r0 and r1.
803
1159
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
804
1160
GenerateRuntimeGetProperty(masm);
1162
__ bind(&check_string);
1163
GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
1165
GenerateKeyedLoadReceiverCheck(
1166
masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1168
// If the receiver is a fast-case object, check the keyed lookup
1169
// cache. Otherwise probe the dictionary.
1170
__ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1171
__ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
1172
__ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1174
__ b(eq, &probe_dictionary);
1176
// Load the map of the receiver, compute the keyed lookup cache hash
1177
// based on 32 bits of the map pointer and the string hash.
1178
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1179
__ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1180
__ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1181
__ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
1182
__ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
1184
// Load the key (consisting of map and symbol) from the cache and
1186
ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
1187
__ mov(r4, Operand(cache_keys));
1188
__ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1189
__ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
1192
__ ldr(r5, MemOperand(r4));
1196
// Get field offset.
1199
// r2 : receiver's map
1200
// r3 : lookup cache index
1201
ExternalReference cache_field_offsets
1202
= ExternalReference::keyed_lookup_cache_field_offsets();
1203
__ mov(r4, Operand(cache_field_offsets));
1204
__ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1205
__ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
1206
__ sub(r5, r5, r6, SetCC);
1207
__ b(ge, &property_array_property);
1209
// Load in-object property.
1210
__ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1211
__ add(r6, r6, r5); // Index from start of object.
1212
__ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1213
__ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1214
__ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1217
// Load property array property.
1218
__ bind(&property_array_property);
1219
__ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1220
__ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1221
__ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
1222
__ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1225
// Do a quick inline probe of the receiver's dictionary, if it
1227
__ bind(&probe_dictionary);
1231
__ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1232
__ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1233
GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
1234
// Load the property to r0.
1235
GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
1236
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
1239
__ bind(&index_string);
1240
GenerateIndexFromHash(masm, key, r3);
1241
// Now jump to the place where smi keys are handled.
808
1246
void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
809
1247
// ---------- S t a t e --------------
810
1248
// -- lr : return address
1249
// -- r0 : key (index)
812
1250
// -- r1 : receiver
813
1251
// -----------------------------------
816
1253
Label index_out_of_range;
817
Label slow_char_code;
820
Register object = r1;
1255
Register receiver = r1;
821
1256
Register index = r0;
823
Register scratch = r3;
825
StringHelper::GenerateFastCharCodeAt(masm,
830
&miss, // When not a string.
835
// If we didn't bail out, code register contains smi tagged char
837
__ bind(&got_char_code);
838
StringHelper::GenerateCharFromCode(masm, code, scratch, r0, JUMP_FUNCTION);
840
__ Abort("Unexpected fall-through from char from code tail call");
843
// Check if key is a heap number.
844
__ bind(&index_not_smi);
845
__ CheckMap(index, scratch, Factory::heap_number_map(), &miss, true);
847
// Push receiver and key on the stack (now that we know they are a
848
// string and a number), and call runtime.
849
__ bind(&slow_char_code);
850
__ EnterInternalFrame();
851
__ Push(object, index);
852
__ CallRuntime(Runtime::kStringCharCodeAt, 2);
853
ASSERT(!code.is(r0));
855
__ LeaveInternalFrame();
857
// Check if the runtime call returned NaN char code. If yes, return
858
// undefined. Otherwise, we can continue.
859
if (FLAG_debug_code) {
860
__ BranchOnSmi(code, &got_char_code);
861
__ ldr(scratch, FieldMemOperand(code, HeapObject::kMapOffset));
862
__ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
864
__ Assert(eq, "StringCharCodeAt must return smi or heap number");
866
__ LoadRoot(scratch, Heap::kNanValueRootIndex);
867
__ cmp(code, scratch);
868
__ b(ne, &got_char_code);
1257
Register scratch1 = r2;
1258
Register scratch2 = r3;
1259
Register result = r0;
1261
StringCharAtGenerator char_at_generator(receiver,
1266
&miss, // When not a string.
1267
&miss, // When not a number.
1268
&index_out_of_range,
1269
STRING_INDEX_IS_ARRAY_INDEX);
1270
char_at_generator.GenerateFast(masm);
1273
ICRuntimeCallHelper call_helper;
1274
char_at_generator.GenerateSlow(masm, call_helper);
869
1276
__ bind(&index_out_of_range);
870
1277
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
874
GenerateGeneric(masm);
1561
1965
if (CpuFeatures::IsSupported(VFP3)) {
1562
1966
CpuFeatures::Scope scope(VFP3);
1564
// vldr requires offset to be a multiple of 4 so we can not
1565
// include -kHeapObjectTag into it.
1566
__ sub(r5, r0, Operand(kHeapObjectTag));
1567
__ vldr(d0, r5, HeapNumber::kValueOffset);
1569
1969
if (array_type == kExternalFloatArray) {
1970
// vldr requires offset to be a multiple of 4 so we can not
1971
// include -kHeapObjectTag into it.
1972
__ sub(r5, r0, Operand(kHeapObjectTag));
1973
__ vldr(d0, r5, HeapNumber::kValueOffset);
1570
1974
__ vcvt_f32_f64(s0, d0);
1571
1975
__ vmov(r5, s0);
1572
1976
__ str(r5, MemOperand(r3, r4, LSL, 2));
1576
1978
// Need to perform float-to-int conversion.
1579
// Move vector status bits to normal status bits.
1580
__ vmrs(v8::internal::pc);
1581
__ mov(r5, Operand(0), LeaveCC, vs); // NaN converts to 0.
1584
// Test whether exponent equal to 0x7FF (infinity or NaN).
1585
__ vmov(r6, r7, d0);
1586
__ mov(r5, Operand(0x7FF00000));
1587
__ and_(r6, r6, Operand(r5));
1588
__ teq(r6, Operand(r5));
1589
__ mov(r6, Operand(0), LeaveCC, eq);
1979
// Test for NaN or infinity (both give zero).
1980
__ ldr(r6, FieldMemOperand(r5, HeapNumber::kExponentOffset));
1982
// Hoisted load. vldr requires offset to be a multiple of 4 so we can not
1983
// include -kHeapObjectTag into it.
1984
__ sub(r5, r0, Operand(kHeapObjectTag));
1985
__ vldr(d0, r5, HeapNumber::kValueOffset);
1987
__ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
1988
// NaNs and Infinities have all-one exponents so they sign extend to -1.
1989
__ cmp(r6, Operand(-1));
1990
__ mov(r5, Operand(Smi::FromInt(0)), LeaveCC, eq);
1591
1992
// Not infinity or NaN simply convert to int.
1592
1993
if (IsElementTypeSigned(array_type)) {