Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / v8 / src / arm / ic-arm.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #if V8_TARGET_ARCH_ARM
31
32 #include "assembler-arm.h"
33 #include "code-stubs.h"
34 #include "codegen.h"
35 #include "disasm.h"
36 #include "ic-inl.h"
37 #include "runtime.h"
38 #include "stub-cache.h"
39
40 namespace v8 {
41 namespace internal {
42
43
44 // ----------------------------------------------------------------------------
45 // Static IC stub generators.
46 //
47
48 #define __ ACCESS_MASM(masm)
49
50
51 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
52                                             Register type,
53                                             Label* global_object) {
54   // Register usage:
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);
62 }
63
64
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 GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
68                                                 Register receiver,
69                                                 Register elements,
70                                                 Register t0,
71                                                 Register t1,
72                                                 Label* miss) {
73   // Register usage:
74   //   receiver: holds the receiver on entry and is unchanged.
75   //   elements: holds the property dictionary on fall through.
76   // Scratch registers:
77   //   t0: used to holds the receiver map.
78   //   t1: used to holds the receiver instance type, receiver bit mask and
79   //       elements map.
80
81   // Check that the receiver isn't a smi.
82   __ JumpIfSmi(receiver, miss);
83
84   // Check that the receiver is a valid JS object.
85   __ CompareObjectType(receiver, t0, t1, FIRST_SPEC_OBJECT_TYPE);
86   __ b(lt, miss);
87
88   // If this assert fails, we have to check upper bound too.
89   STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
90
91   GenerateGlobalInstanceTypeCheck(masm, t1, miss);
92
93   // Check that the global object does not require access checks.
94   __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
95   __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
96                      (1 << Map::kHasNamedInterceptor)));
97   __ b(ne, miss);
98
99   __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
100   __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
101   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
102   __ cmp(t1, ip);
103   __ b(ne, miss);
104 }
105
106
107 // Helper function used from LoadIC GenerateNormal.
108 //
109 // elements: Property dictionary. It is not clobbered if a jump to the miss
110 //           label is done.
111 // name:     Property name. It is not clobbered if a jump to the miss label is
112 //           done
113 // result:   Register for the result. It is only updated if a jump to the miss
114 //           label is not done. Can be the same as elements or name clobbering
115 //           one of these in the case of not jumping to the miss label.
116 // The two scratch registers need to be different from elements, name and
117 // result.
118 // The generated code assumes that the receiver has slow properties,
119 // is not a global object and does not have interceptors.
120 static void GenerateDictionaryLoad(MacroAssembler* masm,
121                                    Label* miss,
122                                    Register elements,
123                                    Register name,
124                                    Register result,
125                                    Register scratch1,
126                                    Register scratch2) {
127   // Main use of the scratch registers.
128   // scratch1: Used as temporary and to hold the capacity of the property
129   //           dictionary.
130   // scratch2: Used as temporary.
131   Label done;
132
133   // Probe the dictionary.
134   NameDictionaryLookupStub::GeneratePositiveLookup(masm,
135                                                    miss,
136                                                    &done,
137                                                    elements,
138                                                    name,
139                                                    scratch1,
140                                                    scratch2);
141
142   // If probing finds an entry check that the value is a normal
143   // property.
144   __ bind(&done);  // scratch2 == elements + 4 * index
145   const int kElementsStartOffset = NameDictionary::kHeaderSize +
146       NameDictionary::kElementsStartIndex * kPointerSize;
147   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
148   __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
149   __ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
150   __ b(ne, miss);
151
152   // Get the value at the masked, scaled index and return.
153   __ ldr(result,
154          FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
155 }
156
157
158 // Helper function used from StoreIC::GenerateNormal.
159 //
160 // elements: Property dictionary. It is not clobbered if a jump to the miss
161 //           label is done.
162 // name:     Property name. It is not clobbered if a jump to the miss label is
163 //           done
164 // value:    The value to store.
165 // The two scratch registers need to be different from elements, name and
166 // result.
167 // The generated code assumes that the receiver has slow properties,
168 // is not a global object and does not have interceptors.
169 static void GenerateDictionaryStore(MacroAssembler* masm,
170                                     Label* miss,
171                                     Register elements,
172                                     Register name,
173                                     Register value,
174                                     Register scratch1,
175                                     Register scratch2) {
176   // Main use of the scratch registers.
177   // scratch1: Used as temporary and to hold the capacity of the property
178   //           dictionary.
179   // scratch2: Used as temporary.
180   Label done;
181
182   // Probe the dictionary.
183   NameDictionaryLookupStub::GeneratePositiveLookup(masm,
184                                                    miss,
185                                                    &done,
186                                                    elements,
187                                                    name,
188                                                    scratch1,
189                                                    scratch2);
190
191   // If probing finds an entry in the dictionary check that the value
192   // is a normal property that is not read only.
193   __ bind(&done);  // scratch2 == elements + 4 * index
194   const int kElementsStartOffset = NameDictionary::kHeaderSize +
195       NameDictionary::kElementsStartIndex * kPointerSize;
196   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
197   const int kTypeAndReadOnlyMask =
198       (PropertyDetails::TypeField::kMask |
199        PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
200   __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
201   __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
202   __ b(ne, miss);
203
204   // Store the value at the masked, scaled index and return.
205   const int kValueOffset = kElementsStartOffset + kPointerSize;
206   __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
207   __ str(value, MemOperand(scratch2));
208
209   // Update the write barrier. Make sure not to clobber the value.
210   __ mov(scratch1, value);
211   __ RecordWrite(
212       elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs);
213 }
214
215
216 // Checks the receiver for special cases (value type, slow case bits).
217 // Falls through for regular JS object.
218 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
219                                            Register receiver,
220                                            Register map,
221                                            Register scratch,
222                                            int interceptor_bit,
223                                            Label* slow) {
224   // Check that the object isn't a smi.
225   __ JumpIfSmi(receiver, slow);
226   // Get the map of the receiver.
227   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
228   // Check bit field.
229   __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
230   __ tst(scratch,
231          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
232   __ b(ne, slow);
233   // Check that the object is some kind of JS object EXCEPT JS Value type.
234   // In the case that the object is a value-wrapper object,
235   // we enter the runtime system to make sure that indexing into string
236   // objects work as intended.
237   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
238   __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
239   __ cmp(scratch, Operand(JS_OBJECT_TYPE));
240   __ b(lt, slow);
241 }
242
243
244 // Loads an indexed element from a fast case array.
245 // If not_fast_array is NULL, doesn't perform the elements map check.
246 static void GenerateFastArrayLoad(MacroAssembler* masm,
247                                   Register receiver,
248                                   Register key,
249                                   Register elements,
250                                   Register scratch1,
251                                   Register scratch2,
252                                   Register result,
253                                   Label* not_fast_array,
254                                   Label* out_of_range) {
255   // Register use:
256   //
257   // receiver - holds the receiver on entry.
258   //            Unchanged unless 'result' is the same register.
259   //
260   // key      - holds the smi key on entry.
261   //            Unchanged unless 'result' is the same register.
262   //
263   // elements - holds the elements of the receiver on exit.
264   //
265   // result   - holds the result on exit if the load succeeded.
266   //            Allowed to be the the same as 'receiver' or 'key'.
267   //            Unchanged on bailout so 'receiver' and 'key' can be safely
268   //            used by further computation.
269   //
270   // Scratch registers:
271   //
272   // scratch1 - used to hold elements map and elements length.
273   //            Holds the elements map if not_fast_array branch is taken.
274   //
275   // scratch2 - used to hold the loaded value.
276
277   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
278   if (not_fast_array != NULL) {
279     // Check that the object is in fast mode and writable.
280     __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
281     __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
282     __ cmp(scratch1, ip);
283     __ b(ne, not_fast_array);
284   } else {
285     __ AssertFastElements(elements);
286   }
287   // Check that the key (index) is within bounds.
288   __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
289   __ cmp(key, Operand(scratch1));
290   __ b(hs, out_of_range);
291   // Fast case: Do the load.
292   __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
293   __ ldr(scratch2, MemOperand::PointerAddressFromSmiKey(scratch1, key));
294   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
295   __ cmp(scratch2, ip);
296   // In case the loaded value is the_hole we have to consult GetProperty
297   // to ensure the prototype chain is searched.
298   __ b(eq, out_of_range);
299   __ mov(result, scratch2);
300 }
301
302
303 // Checks whether a key is an array index string or a unique name.
304 // Falls through if a key is a unique name.
305 static void GenerateKeyNameCheck(MacroAssembler* masm,
306                                  Register key,
307                                  Register map,
308                                  Register hash,
309                                  Label* index_string,
310                                  Label* not_unique) {
311   // The key is not a smi.
312   Label unique;
313   // Is it a name?
314   __ CompareObjectType(key, map, hash, LAST_UNIQUE_NAME_TYPE);
315   __ b(hi, not_unique);
316   STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
317   __ b(eq, &unique);
318
319   // Is the string an array index, with cached numeric value?
320   __ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
321   __ tst(hash, Operand(Name::kContainsCachedArrayIndexMask));
322   __ b(eq, index_string);
323
324   // Is the string internalized? We know it's a string, so a single
325   // bit test is enough.
326   // map: key map
327   __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
328   STATIC_ASSERT(kInternalizedTag == 0);
329   __ tst(hash, Operand(kIsNotInternalizedMask));
330   __ b(ne, not_unique);
331
332   __ bind(&unique);
333 }
334
335
336 void LoadIC::GenerateMegamorphic(MacroAssembler* masm,
337                                  ExtraICState extra_state) {
338   // ----------- S t a t e -------------
339   //  -- r2    : name
340   //  -- lr    : return address
341   //  -- r0    : receiver
342   // -----------------------------------
343
344   // Probe the stub cache.
345   Code::Flags flags = Code::ComputeFlags(
346       Code::HANDLER, MONOMORPHIC, extra_state,
347       Code::NORMAL, Code::LOAD_IC);
348   masm->isolate()->stub_cache()->GenerateProbe(
349       masm, flags, r0, r2, r3, r4, r5, r6);
350
351   // Cache miss: Jump to runtime.
352   GenerateMiss(masm);
353 }
354
355
356 void LoadIC::GenerateNormal(MacroAssembler* masm) {
357   // ----------- S t a t e -------------
358   //  -- r2    : name
359   //  -- lr    : return address
360   //  -- r0    : receiver
361   // -----------------------------------
362   Label miss;
363
364   GenerateNameDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
365
366   // r1: elements
367   GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
368   __ Ret();
369
370   // Cache miss: Jump to runtime.
371   __ bind(&miss);
372   GenerateMiss(masm);
373 }
374
375
376 void LoadIC::GenerateMiss(MacroAssembler* masm) {
377   // ----------- S t a t e -------------
378   //  -- r2    : name
379   //  -- lr    : return address
380   //  -- r0    : receiver
381   // -----------------------------------
382   Isolate* isolate = masm->isolate();
383
384   __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
385
386   __ mov(r3, r0);
387   __ Push(r3, r2);
388
389   // Perform tail call to the entry.
390   ExternalReference ref =
391       ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
392   __ TailCallExternalReference(ref, 2, 1);
393 }
394
395
396 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
397   // ---------- S t a t e --------------
398   //  -- r2    : name
399   //  -- lr    : return address
400   //  -- r0    : receiver
401   // -----------------------------------
402
403   __ mov(r3, r0);
404   __ Push(r3, r2);
405
406   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
407 }
408
409
410 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
411                                                 Register object,
412                                                 Register key,
413                                                 Register scratch1,
414                                                 Register scratch2,
415                                                 Register scratch3,
416                                                 Label* unmapped_case,
417                                                 Label* slow_case) {
418   Heap* heap = masm->isolate()->heap();
419
420   // Check that the receiver is a JSObject. Because of the map check
421   // later, we do not need to check for interceptors or whether it
422   // requires access checks.
423   __ JumpIfSmi(object, slow_case);
424   // Check that the object is some kind of JSObject.
425   __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE);
426   __ b(lt, slow_case);
427
428   // Check that the key is a positive smi.
429   __ tst(key, Operand(0x80000001));
430   __ b(ne, slow_case);
431
432   // Load the elements into scratch1 and check its map.
433   Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
434   __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
435   __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
436
437   // Check if element is in the range of mapped arguments. If not, jump
438   // to the unmapped lookup with the parameter map in scratch1.
439   __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
440   __ sub(scratch2, scratch2, Operand(Smi::FromInt(2)));
441   __ cmp(key, Operand(scratch2));
442   __ b(cs, unmapped_case);
443
444   // Load element index and check whether it is the hole.
445   const int kOffset =
446       FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
447
448   __ mov(scratch3, Operand(kPointerSize >> 1));
449   __ mul(scratch3, key, scratch3);
450   __ add(scratch3, scratch3, Operand(kOffset));
451
452   __ ldr(scratch2, MemOperand(scratch1, scratch3));
453   __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
454   __ cmp(scratch2, scratch3);
455   __ b(eq, unmapped_case);
456
457   // Load value from context and return it. We can reuse scratch1 because
458   // we do not jump to the unmapped lookup (which requires the parameter
459   // map in scratch1).
460   __ ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
461   __ mov(scratch3, Operand(kPointerSize >> 1));
462   __ mul(scratch3, scratch2, scratch3);
463   __ add(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
464   return MemOperand(scratch1, scratch3);
465 }
466
467
468 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
469                                                   Register key,
470                                                   Register parameter_map,
471                                                   Register scratch,
472                                                   Label* slow_case) {
473   // Element is in arguments backing store, which is referenced by the
474   // second element of the parameter_map. The parameter_map register
475   // must be loaded with the parameter map of the arguments object and is
476   // overwritten.
477   const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
478   Register backing_store = parameter_map;
479   __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
480   Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
481   __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
482               DONT_DO_SMI_CHECK);
483   __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
484   __ cmp(key, Operand(scratch));
485   __ b(cs, slow_case);
486   __ mov(scratch, Operand(kPointerSize >> 1));
487   __ mul(scratch, key, scratch);
488   __ add(scratch,
489          scratch,
490          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
491   return MemOperand(backing_store, scratch);
492 }
493
494
495 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
496   // ---------- S t a t e --------------
497   //  -- lr     : return address
498   //  -- r0     : key
499   //  -- r1     : receiver
500   // -----------------------------------
501   Label slow, notin;
502   MemOperand mapped_location =
503       GenerateMappedArgumentsLookup(masm, r1, r0, r2, r3, r4, &notin, &slow);
504   __ ldr(r0, mapped_location);
505   __ Ret();
506   __ bind(&notin);
507   // The unmapped lookup expects that the parameter map is in r2.
508   MemOperand unmapped_location =
509       GenerateUnmappedArgumentsLookup(masm, r0, r2, r3, &slow);
510   __ ldr(r2, unmapped_location);
511   __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
512   __ cmp(r2, r3);
513   __ b(eq, &slow);
514   __ mov(r0, r2);
515   __ Ret();
516   __ bind(&slow);
517   GenerateMiss(masm);
518 }
519
520
521 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
522   // ---------- S t a t e --------------
523   //  -- r0     : value
524   //  -- r1     : key
525   //  -- r2     : receiver
526   //  -- lr     : return address
527   // -----------------------------------
528   Label slow, notin;
529   MemOperand mapped_location =
530       GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, &notin, &slow);
531   __ str(r0, mapped_location);
532   __ add(r6, r3, r5);
533   __ mov(r9, r0);
534   __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
535   __ Ret();
536   __ bind(&notin);
537   // The unmapped lookup expects that the parameter map is in r3.
538   MemOperand unmapped_location =
539       GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
540   __ str(r0, unmapped_location);
541   __ add(r6, r3, r4);
542   __ mov(r9, r0);
543   __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
544   __ Ret();
545   __ bind(&slow);
546   GenerateMiss(masm);
547 }
548
549
550 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
551   // ---------- S t a t e --------------
552   //  -- lr     : return address
553   //  -- r0     : key
554   //  -- r1     : receiver
555   // -----------------------------------
556   Isolate* isolate = masm->isolate();
557
558   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
559
560   __ Push(r1, r0);
561
562   // Perform tail call to the entry.
563   ExternalReference ref =
564       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
565
566   __ TailCallExternalReference(ref, 2, 1);
567 }
568
569
570 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
571   // ---------- S t a t e --------------
572   //  -- lr     : return address
573   //  -- r0     : key
574   //  -- r1     : receiver
575   // -----------------------------------
576
577   __ Push(r1, r0);
578
579   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
580 }
581
582
583 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
584   // ---------- S t a t e --------------
585   //  -- lr     : return address
586   //  -- r0     : key
587   //  -- r1     : receiver
588   // -----------------------------------
589   Label slow, check_name, index_smi, index_name, property_array_property;
590   Label probe_dictionary, check_number_dictionary;
591
592   Register key = r0;
593   Register receiver = r1;
594
595   Isolate* isolate = masm->isolate();
596
597   // Check that the key is a smi.
598   __ JumpIfNotSmi(key, &check_name);
599   __ bind(&index_smi);
600   // Now the key is known to be a smi. This place is also jumped to from below
601   // where a numeric string is converted to a smi.
602
603   GenerateKeyedLoadReceiverCheck(
604       masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
605
606   // Check the receiver's map to see if it has fast elements.
607   __ CheckFastElements(r2, r3, &check_number_dictionary);
608
609   GenerateFastArrayLoad(
610       masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
611   __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
612   __ Ret();
613
614   __ bind(&check_number_dictionary);
615   __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
616   __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
617
618   // Check whether the elements is a number dictionary.
619   // r0: key
620   // r3: elements map
621   // r4: elements
622   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
623   __ cmp(r3, ip);
624   __ b(ne, &slow);
625   __ SmiUntag(r2, r0);
626   __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5);
627   __ Ret();
628
629   // Slow case, key and receiver still in r0 and r1.
630   __ bind(&slow);
631   __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
632                       1, r2, r3);
633   GenerateRuntimeGetProperty(masm);
634
635   __ bind(&check_name);
636   GenerateKeyNameCheck(masm, key, r2, r3, &index_name, &slow);
637
638   GenerateKeyedLoadReceiverCheck(
639       masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
640
641   // If the receiver is a fast-case object, check the keyed lookup
642   // cache. Otherwise probe the dictionary.
643   __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
644   __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
645   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
646   __ cmp(r4, ip);
647   __ b(eq, &probe_dictionary);
648
649   // Load the map of the receiver, compute the keyed lookup cache hash
650   // based on 32 bits of the map pointer and the name hash.
651   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
652   __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
653   __ ldr(r4, FieldMemOperand(r0, Name::kHashFieldOffset));
654   __ eor(r3, r3, Operand(r4, ASR, Name::kHashShift));
655   int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
656   __ And(r3, r3, Operand(mask));
657
658   // Load the key (consisting of map and unique name) from the cache and
659   // check for match.
660   Label load_in_object_property;
661   static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
662   Label hit_on_nth_entry[kEntriesPerBucket];
663   ExternalReference cache_keys =
664       ExternalReference::keyed_lookup_cache_keys(isolate);
665
666   __ mov(r4, Operand(cache_keys));
667   __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
668
669   for (int i = 0; i < kEntriesPerBucket - 1; i++) {
670     Label try_next_entry;
671     // Load map and move r4 to next entry.
672     __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex));
673     __ cmp(r2, r5);
674     __ b(ne, &try_next_entry);
675     __ ldr(r5, MemOperand(r4, -kPointerSize));  // Load name
676     __ cmp(r0, r5);
677     __ b(eq, &hit_on_nth_entry[i]);
678     __ bind(&try_next_entry);
679   }
680
681   // Last entry: Load map and move r4 to name.
682   __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));
683   __ cmp(r2, r5);
684   __ b(ne, &slow);
685   __ ldr(r5, MemOperand(r4));
686   __ cmp(r0, r5);
687   __ b(ne, &slow);
688
689   // Get field offset.
690   // r0     : key
691   // r1     : receiver
692   // r2     : receiver's map
693   // r3     : lookup cache index
694   ExternalReference cache_field_offsets =
695       ExternalReference::keyed_lookup_cache_field_offsets(isolate);
696
697   // Hit on nth entry.
698   for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
699     __ bind(&hit_on_nth_entry[i]);
700     __ mov(r4, Operand(cache_field_offsets));
701     if (i != 0) {
702       __ add(r3, r3, Operand(i));
703     }
704     __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
705     __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
706     __ sub(r5, r5, r6, SetCC);
707     __ b(ge, &property_array_property);
708     if (i != 0) {
709       __ jmp(&load_in_object_property);
710     }
711   }
712
713   // Load in-object property.
714   __ bind(&load_in_object_property);
715   __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
716   __ add(r6, r6, r5);  // Index from start of object.
717   __ sub(r1, r1, Operand(kHeapObjectTag));  // Remove the heap tag.
718   __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
719   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
720                       1, r2, r3);
721   __ Ret();
722
723   // Load property array property.
724   __ bind(&property_array_property);
725   __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
726   __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
727   __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
728   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
729                       1, r2, r3);
730   __ Ret();
731
732   // Do a quick inline probe of the receiver's dictionary, if it
733   // exists.
734   __ bind(&probe_dictionary);
735   // r1: receiver
736   // r0: key
737   // r3: elements
738   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
739   __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
740   GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
741   // Load the property to r0.
742   GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
743   __ IncrementCounter(
744       isolate->counters()->keyed_load_generic_symbol(), 1, r2, r3);
745   __ Ret();
746
747   __ bind(&index_name);
748   __ IndexFromHash(r3, key);
749   // Now jump to the place where smi keys are handled.
750   __ jmp(&index_smi);
751 }
752
753
754 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
755   // ---------- S t a t e --------------
756   //  -- lr     : return address
757   //  -- r0     : key (index)
758   //  -- r1     : receiver
759   // -----------------------------------
760   Label miss;
761
762   Register receiver = r1;
763   Register index = r0;
764   Register scratch = r3;
765   Register result = r0;
766
767   StringCharAtGenerator char_at_generator(receiver,
768                                           index,
769                                           scratch,
770                                           result,
771                                           &miss,  // When not a string.
772                                           &miss,  // When not a number.
773                                           &miss,  // When index out of range.
774                                           STRING_INDEX_IS_ARRAY_INDEX);
775   char_at_generator.GenerateFast(masm);
776   __ Ret();
777
778   StubRuntimeCallHelper call_helper;
779   char_at_generator.GenerateSlow(masm, call_helper);
780
781   __ bind(&miss);
782   GenerateMiss(masm);
783 }
784
785
786 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
787   // ---------- S t a t e --------------
788   //  -- lr     : return address
789   //  -- r0     : key
790   //  -- r1     : receiver
791   // -----------------------------------
792   Label slow;
793
794   // Check that the receiver isn't a smi.
795   __ JumpIfSmi(r1, &slow);
796
797   // Check that the key is an array index, that is Uint32.
798   __ NonNegativeSmiTst(r0);
799   __ b(ne, &slow);
800
801   // Get the map of the receiver.
802   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
803
804   // Check that it has indexed interceptor and access checks
805   // are not enabled for this object.
806   __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
807   __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
808   __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
809   __ b(ne, &slow);
810
811   // Everything is fine, call runtime.
812   __ Push(r1, r0);  // Receiver, key.
813
814   // Perform tail call to the entry.
815   __ TailCallExternalReference(
816       ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
817                         masm->isolate()),
818       2,
819       1);
820
821   __ bind(&slow);
822   GenerateMiss(masm);
823 }
824
825
826 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
827   // ---------- S t a t e --------------
828   //  -- r0     : value
829   //  -- r1     : key
830   //  -- r2     : receiver
831   //  -- lr     : return address
832   // -----------------------------------
833
834   // Push receiver, key and value for runtime call.
835   __ Push(r2, r1, r0);
836
837   ExternalReference ref =
838       ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
839   __ TailCallExternalReference(ref, 3, 1);
840 }
841
842
843 void StoreIC::GenerateSlow(MacroAssembler* masm) {
844   // ---------- S t a t e --------------
845   //  -- r0     : value
846   //  -- r2     : key
847   //  -- r1     : receiver
848   //  -- lr     : return address
849   // -----------------------------------
850
851   // Push receiver, key and value for runtime call.
852   __ Push(r1, r2, r0);
853
854   // The slow case calls into the runtime to complete the store without causing
855   // an IC miss that would otherwise cause a transition to the generic stub.
856   ExternalReference ref =
857       ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate());
858   __ TailCallExternalReference(ref, 3, 1);
859 }
860
861
862 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
863   // ---------- S t a t e --------------
864   //  -- r0     : value
865   //  -- r1     : key
866   //  -- r2     : receiver
867   //  -- lr     : return address
868   // -----------------------------------
869
870   // Push receiver, key and value for runtime call.
871   __ Push(r2, r1, r0);
872
873   // The slow case calls into the runtime to complete the store without causing
874   // an IC miss that would otherwise cause a transition to the generic stub.
875   ExternalReference ref =
876       ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
877   __ TailCallExternalReference(ref, 3, 1);
878 }
879
880
881 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
882                                               StrictModeFlag strict_mode) {
883   // ---------- S t a t e --------------
884   //  -- r0     : value
885   //  -- r1     : key
886   //  -- r2     : receiver
887   //  -- lr     : return address
888   // -----------------------------------
889
890   // Push receiver, key and value for runtime call.
891   __ Push(r2, r1, r0);
892
893   __ mov(r1, Operand(Smi::FromInt(NONE)));          // PropertyAttributes
894   __ mov(r0, Operand(Smi::FromInt(strict_mode)));   // Strict mode.
895   __ Push(r1, r0);
896
897   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
898 }
899
900
901 static void KeyedStoreGenerateGenericHelper(
902     MacroAssembler* masm,
903     Label* fast_object,
904     Label* fast_double,
905     Label* slow,
906     KeyedStoreCheckMap check_map,
907     KeyedStoreIncrementLength increment_length,
908     Register value,
909     Register key,
910     Register receiver,
911     Register receiver_map,
912     Register elements_map,
913     Register elements) {
914   Label transition_smi_elements;
915   Label finish_object_store, non_double_value, transition_double_elements;
916   Label fast_double_without_map_check;
917
918   // Fast case: Do the store, could be either Object or double.
919   __ bind(fast_object);
920   Register scratch_value = r4;
921   Register address = r5;
922   if (check_map == kCheckMap) {
923     __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
924     __ cmp(elements_map,
925            Operand(masm->isolate()->factory()->fixed_array_map()));
926     __ b(ne, fast_double);
927   }
928
929   // HOLECHECK: guards "A[i] = V"
930   // We have to go to the runtime if the current value is the hole because
931   // there may be a callback on the element
932   Label holecheck_passed1;
933   __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
934   __ ldr(scratch_value,
935          MemOperand::PointerAddressFromSmiKey(address, key, PreIndex));
936   __ cmp(scratch_value, Operand(masm->isolate()->factory()->the_hole_value()));
937   __ b(ne, &holecheck_passed1);
938   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
939                                       slow);
940
941   __ bind(&holecheck_passed1);
942
943   // Smi stores don't require further checks.
944   Label non_smi_value;
945   __ JumpIfNotSmi(value, &non_smi_value);
946
947   if (increment_length == kIncrementLength) {
948     // Add 1 to receiver->length.
949     __ add(scratch_value, key, Operand(Smi::FromInt(1)));
950     __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
951   }
952   // It's irrelevant whether array is smi-only or not when writing a smi.
953   __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
954   __ str(value, MemOperand::PointerAddressFromSmiKey(address, key));
955   __ Ret();
956
957   __ bind(&non_smi_value);
958   // Escape to elements kind transition case.
959   __ CheckFastObjectElements(receiver_map, scratch_value,
960                              &transition_smi_elements);
961
962   // Fast elements array, store the value to the elements backing store.
963   __ bind(&finish_object_store);
964   if (increment_length == kIncrementLength) {
965     // Add 1 to receiver->length.
966     __ add(scratch_value, key, Operand(Smi::FromInt(1)));
967     __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
968   }
969   __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
970   __ add(address, address, Operand::PointerOffsetFromSmiKey(key));
971   __ str(value, MemOperand(address));
972   // Update write barrier for the elements array address.
973   __ mov(scratch_value, value);  // Preserve the value which is returned.
974   __ RecordWrite(elements,
975                  address,
976                  scratch_value,
977                  kLRHasNotBeenSaved,
978                  kDontSaveFPRegs,
979                  EMIT_REMEMBERED_SET,
980                  OMIT_SMI_CHECK);
981   __ Ret();
982
983   __ bind(fast_double);
984   if (check_map == kCheckMap) {
985     // Check for fast double array case. If this fails, call through to the
986     // runtime.
987     __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
988     __ b(ne, slow);
989   }
990
991   // HOLECHECK: guards "A[i] double hole?"
992   // We have to see if the double version of the hole is present. If so
993   // go to the runtime.
994   __ add(address, elements,
995          Operand((FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32))
996                  - kHeapObjectTag));
997   __ ldr(scratch_value,
998          MemOperand(address, key, LSL, kPointerSizeLog2, PreIndex));
999   __ cmp(scratch_value, Operand(kHoleNanUpper32));
1000   __ b(ne, &fast_double_without_map_check);
1001   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
1002                                       slow);
1003
1004   __ bind(&fast_double_without_map_check);
1005   __ StoreNumberToDoubleElements(value, key, elements, r3, d0,
1006                                  &transition_double_elements);
1007   if (increment_length == kIncrementLength) {
1008     // Add 1 to receiver->length.
1009     __ add(scratch_value, key, Operand(Smi::FromInt(1)));
1010     __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1011   }
1012   __ Ret();
1013
1014   __ bind(&transition_smi_elements);
1015   // Transition the array appropriately depending on the value type.
1016   __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
1017   __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
1018   __ b(ne, &non_double_value);
1019
1020   // Value is a double. Transition FAST_SMI_ELEMENTS ->
1021   // FAST_DOUBLE_ELEMENTS and complete the store.
1022   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1023                                          FAST_DOUBLE_ELEMENTS,
1024                                          receiver_map,
1025                                          r4,
1026                                          slow);
1027   ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
1028   AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
1029                                                     FAST_DOUBLE_ELEMENTS);
1030   ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
1031   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1032   __ jmp(&fast_double_without_map_check);
1033
1034   __ bind(&non_double_value);
1035   // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
1036   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1037                                          FAST_ELEMENTS,
1038                                          receiver_map,
1039                                          r4,
1040                                          slow);
1041   ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
1042   mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
1043   ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
1044                                                                    slow);
1045   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1046   __ jmp(&finish_object_store);
1047
1048   __ bind(&transition_double_elements);
1049   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
1050   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
1051   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1052   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1053                                          FAST_ELEMENTS,
1054                                          receiver_map,
1055                                          r4,
1056                                          slow);
1057   ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
1058   mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
1059   ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
1060   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1061   __ jmp(&finish_object_store);
1062 }
1063
1064
1065 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1066                                    StrictModeFlag strict_mode) {
1067   // ---------- S t a t e --------------
1068   //  -- r0     : value
1069   //  -- r1     : key
1070   //  -- r2     : receiver
1071   //  -- lr     : return address
1072   // -----------------------------------
1073   Label slow, fast_object, fast_object_grow;
1074   Label fast_double, fast_double_grow;
1075   Label array, extra, check_if_double_array;
1076
1077   // Register usage.
1078   Register value = r0;
1079   Register key = r1;
1080   Register receiver = r2;
1081   Register receiver_map = r3;
1082   Register elements_map = r6;
1083   Register elements = r9;  // Elements array of the receiver.
1084   // r4 and r5 are used as general scratch registers.
1085
1086   // Check that the key is a smi.
1087   __ JumpIfNotSmi(key, &slow);
1088   // Check that the object isn't a smi.
1089   __ JumpIfSmi(receiver, &slow);
1090   // Get the map of the object.
1091   __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1092   // Check that the receiver does not require access checks and is not observed.
1093   // The generic stub does not perform map checks or handle observed objects.
1094   __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
1095   __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
1096   __ b(ne, &slow);
1097   // Check if the object is a JS array or not.
1098   __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
1099   __ cmp(r4, Operand(JS_ARRAY_TYPE));
1100   __ b(eq, &array);
1101   // Check that the object is some kind of JSObject.
1102   __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
1103   __ b(lt, &slow);
1104
1105   // Object case: Check key against length in the elements array.
1106   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1107   // Check array bounds. Both the key and the length of FixedArray are smis.
1108   __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1109   __ cmp(key, Operand(ip));
1110   __ b(lo, &fast_object);
1111
1112   // Slow case, handle jump to runtime.
1113   __ bind(&slow);
1114   // Entry registers are intact.
1115   // r0: value.
1116   // r1: key.
1117   // r2: receiver.
1118   GenerateRuntimeSetProperty(masm, strict_mode);
1119
1120   // Extra capacity case: Check if there is extra capacity to
1121   // perform the store and update the length. Used for adding one
1122   // element to the array by writing to array[array.length].
1123   __ bind(&extra);
1124   // Condition code from comparing key and array length is still available.
1125   __ b(ne, &slow);  // Only support writing to writing to array[array.length].
1126   // Check for room in the elements backing store.
1127   // Both the key and the length of FixedArray are smis.
1128   __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1129   __ cmp(key, Operand(ip));
1130   __ b(hs, &slow);
1131   __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1132   __ cmp(elements_map,
1133          Operand(masm->isolate()->factory()->fixed_array_map()));
1134   __ b(ne, &check_if_double_array);
1135   __ jmp(&fast_object_grow);
1136
1137   __ bind(&check_if_double_array);
1138   __ cmp(elements_map,
1139          Operand(masm->isolate()->factory()->fixed_double_array_map()));
1140   __ b(ne, &slow);
1141   __ jmp(&fast_double_grow);
1142
1143   // Array case: Get the length and the elements array from the JS
1144   // array. Check that the array is in fast mode (and writable); if it
1145   // is the length is always a smi.
1146   __ bind(&array);
1147   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1148
1149   // Check the key against the length in the array.
1150   __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1151   __ cmp(key, Operand(ip));
1152   __ b(hs, &extra);
1153
1154   KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
1155                                   &slow, kCheckMap, kDontIncrementLength,
1156                                   value, key, receiver, receiver_map,
1157                                   elements_map, elements);
1158   KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
1159                                   &slow, kDontCheckMap, kIncrementLength,
1160                                   value, key, receiver, receiver_map,
1161                                   elements_map, elements);
1162 }
1163
1164
1165 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1166                                   ExtraICState extra_ic_state) {
1167   // ----------- S t a t e -------------
1168   //  -- r0    : value
1169   //  -- r1    : receiver
1170   //  -- r2    : name
1171   //  -- lr    : return address
1172   // -----------------------------------
1173
1174   // Get the receiver from the stack and probe the stub cache.
1175   Code::Flags flags = Code::ComputeFlags(
1176       Code::HANDLER, MONOMORPHIC, extra_ic_state,
1177       Code::NORMAL, Code::STORE_IC);
1178
1179   masm->isolate()->stub_cache()->GenerateProbe(
1180       masm, flags, r1, r2, r3, r4, r5, r6);
1181
1182   // Cache miss: Jump to runtime.
1183   GenerateMiss(masm);
1184 }
1185
1186
1187 void StoreIC::GenerateMiss(MacroAssembler* masm) {
1188   // ----------- S t a t e -------------
1189   //  -- r0    : value
1190   //  -- r1    : receiver
1191   //  -- r2    : name
1192   //  -- lr    : return address
1193   // -----------------------------------
1194
1195   __ Push(r1, r2, r0);
1196
1197   // Perform tail call to the entry.
1198   ExternalReference ref =
1199       ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1200   __ TailCallExternalReference(ref, 3, 1);
1201 }
1202
1203
1204 void StoreIC::GenerateNormal(MacroAssembler* masm) {
1205   // ----------- S t a t e -------------
1206   //  -- r0    : value
1207   //  -- r1    : receiver
1208   //  -- r2    : name
1209   //  -- lr    : return address
1210   // -----------------------------------
1211   Label miss;
1212
1213   GenerateNameDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1214
1215   GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
1216   Counters* counters = masm->isolate()->counters();
1217   __ IncrementCounter(counters->store_normal_hit(),
1218                       1, r4, r5);
1219   __ Ret();
1220
1221   __ bind(&miss);
1222   __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
1223   GenerateMiss(masm);
1224 }
1225
1226
1227 void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1228                                          StrictModeFlag strict_mode) {
1229   // ----------- S t a t e -------------
1230   //  -- r0    : value
1231   //  -- r1    : receiver
1232   //  -- r2    : name
1233   //  -- lr    : return address
1234   // -----------------------------------
1235
1236   __ Push(r1, r2, r0);
1237
1238   __ mov(r1, Operand(Smi::FromInt(NONE)));  // PropertyAttributes
1239   __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1240   __ Push(r1, r0);
1241
1242   // Do tail-call to runtime routine.
1243   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1244 }
1245
1246
1247 #undef __
1248
1249
1250 Condition CompareIC::ComputeCondition(Token::Value op) {
1251   switch (op) {
1252     case Token::EQ_STRICT:
1253     case Token::EQ:
1254       return eq;
1255     case Token::LT:
1256       return lt;
1257     case Token::GT:
1258       return gt;
1259     case Token::LTE:
1260       return le;
1261     case Token::GTE:
1262       return ge;
1263     default:
1264       UNREACHABLE();
1265       return kNoCondition;
1266   }
1267 }
1268
1269
1270 bool CompareIC::HasInlinedSmiCode(Address address) {
1271   // The address of the instruction following the call.
1272   Address cmp_instruction_address =
1273       Assembler::return_address_from_call_start(address);
1274
1275   // If the instruction following the call is not a cmp rx, #yyy, nothing
1276   // was inlined.
1277   Instr instr = Assembler::instr_at(cmp_instruction_address);
1278   return Assembler::IsCmpImmediate(instr);
1279 }
1280
1281
1282 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
1283   Address cmp_instruction_address =
1284       Assembler::return_address_from_call_start(address);
1285
1286   // If the instruction following the call is not a cmp rx, #yyy, nothing
1287   // was inlined.
1288   Instr instr = Assembler::instr_at(cmp_instruction_address);
1289   if (!Assembler::IsCmpImmediate(instr)) {
1290     return;
1291   }
1292
1293   // The delta to the start of the map check instruction and the
1294   // condition code uses at the patched jump.
1295   int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1296   delta +=
1297       Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1298   // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1299   // nothing was inlined.
1300   if (delta == 0) {
1301     return;
1302   }
1303
1304   if (FLAG_trace_ic) {
1305     PrintF("[  patching ic at %p, cmp=%p, delta=%d\n",
1306            address, cmp_instruction_address, delta);
1307   }
1308
1309   Address patch_address =
1310       cmp_instruction_address - delta * Instruction::kInstrSize;
1311   Instr instr_at_patch = Assembler::instr_at(patch_address);
1312   Instr branch_instr =
1313       Assembler::instr_at(patch_address + Instruction::kInstrSize);
1314   // This is patching a conditional "jump if not smi/jump if smi" site.
1315   // Enabling by changing from
1316   //   cmp rx, rx
1317   //   b eq/ne, <target>
1318   // to
1319   //   tst rx, #kSmiTagMask
1320   //   b ne/eq, <target>
1321   // and vice-versa to be disabled again.
1322   CodePatcher patcher(patch_address, 2);
1323   Register reg = Assembler::GetRn(instr_at_patch);
1324   if (check == ENABLE_INLINED_SMI_CHECK) {
1325     ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1326     ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1327               Assembler::GetRm(instr_at_patch).code());
1328     patcher.masm()->tst(reg, Operand(kSmiTagMask));
1329   } else {
1330     ASSERT(check == DISABLE_INLINED_SMI_CHECK);
1331     ASSERT(Assembler::IsTstImmediate(instr_at_patch));
1332     patcher.masm()->cmp(reg, reg);
1333   }
1334   ASSERT(Assembler::IsBranch(branch_instr));
1335   if (Assembler::GetCondition(branch_instr) == eq) {
1336     patcher.EmitCondition(ne);
1337   } else {
1338     ASSERT(Assembler::GetCondition(branch_instr) == ne);
1339     patcher.EmitCondition(eq);
1340   }
1341 }
1342
1343
1344 } }  // namespace v8::internal
1345
1346 #endif  // V8_TARGET_ARCH_ARM