Updated V8 from git://github.com/v8/v8.git to 57f8959fb264354ba1a2e5118db512f588917061
[profile/ivi/qtjsbackend.git] / src / 3rdparty / 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 defined(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 GenerateStringDictionaryReceiverCheck(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/CallIC 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   StringDictionaryLookupStub::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 = StringDictionary::kHeaderSize +
146       StringDictionary::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   StringDictionaryLookupStub::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 = StringDictionary::kHeaderSize +
195       StringDictionary::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 void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
217   // ----------- S t a t e -------------
218   //  -- r2    : name
219   //  -- lr    : return address
220   //  -- r0    : receiver
221   //  -- sp[0] : receiver
222   // -----------------------------------
223   Label miss;
224
225   StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
226   __ bind(&miss);
227   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
228 }
229
230
231 void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
232   // ----------- S t a t e -------------
233   //  -- r2    : name
234   //  -- lr    : return address
235   //  -- r0    : receiver
236   //  -- sp[0] : receiver
237   // -----------------------------------
238   Label miss;
239
240   StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
241                                          support_wrappers);
242   // Cache miss: Jump to runtime.
243   __ bind(&miss);
244   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
245 }
246
247
248 void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
249   // ----------- S t a t e -------------
250   //  -- r2    : name
251   //  -- lr    : return address
252   //  -- r0    : receiver
253   //  -- sp[0] : receiver
254   // -----------------------------------
255   Label miss;
256
257   StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
258   __ bind(&miss);
259   StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
260 }
261
262
263 // Checks the receiver for special cases (value type, slow case bits).
264 // Falls through for regular JS object.
265 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
266                                            Register receiver,
267                                            Register map,
268                                            Register scratch,
269                                            int interceptor_bit,
270                                            Label* slow) {
271   // Check that the object isn't a smi.
272   __ JumpIfSmi(receiver, slow);
273   // Get the map of the receiver.
274   __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
275   // Check bit field.
276   __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
277   __ tst(scratch,
278          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
279   __ b(ne, slow);
280   // Check that the object is some kind of JS object EXCEPT JS Value type.
281   // In the case that the object is a value-wrapper object,
282   // we enter the runtime system to make sure that indexing into string
283   // objects work as intended.
284   ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
285   __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
286   __ cmp(scratch, Operand(JS_OBJECT_TYPE));
287   __ b(lt, slow);
288 }
289
290
291 // Loads an indexed element from a fast case array.
292 // If not_fast_array is NULL, doesn't perform the elements map check.
293 static void GenerateFastArrayLoad(MacroAssembler* masm,
294                                   Register receiver,
295                                   Register key,
296                                   Register elements,
297                                   Register scratch1,
298                                   Register scratch2,
299                                   Register result,
300                                   Label* not_fast_array,
301                                   Label* out_of_range) {
302   // Register use:
303   //
304   // receiver - holds the receiver on entry.
305   //            Unchanged unless 'result' is the same register.
306   //
307   // key      - holds the smi key on entry.
308   //            Unchanged unless 'result' is the same register.
309   //
310   // elements - holds the elements of the receiver on exit.
311   //
312   // result   - holds the result on exit if the load succeeded.
313   //            Allowed to be the the same as 'receiver' or 'key'.
314   //            Unchanged on bailout so 'receiver' and 'key' can be safely
315   //            used by further computation.
316   //
317   // Scratch registers:
318   //
319   // scratch1 - used to hold elements map and elements length.
320   //            Holds the elements map if not_fast_array branch is taken.
321   //
322   // scratch2 - used to hold the loaded value.
323
324   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
325   if (not_fast_array != NULL) {
326     // Check that the object is in fast mode and writable.
327     __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
328     __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
329     __ cmp(scratch1, ip);
330     __ b(ne, not_fast_array);
331   } else {
332     __ AssertFastElements(elements);
333   }
334   // Check that the key (index) is within bounds.
335   __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
336   __ cmp(key, Operand(scratch1));
337   __ b(hs, out_of_range);
338   // Fast case: Do the load.
339   __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
340   // The key is a smi.
341   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
342   __ ldr(scratch2,
343          MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
344   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
345   __ cmp(scratch2, ip);
346   // In case the loaded value is the_hole we have to consult GetProperty
347   // to ensure the prototype chain is searched.
348   __ b(eq, out_of_range);
349   __ mov(result, scratch2);
350 }
351
352
353 // Checks whether a key is an array index string or a symbol string.
354 // Falls through if a key is a symbol.
355 static void GenerateKeyStringCheck(MacroAssembler* masm,
356                                    Register key,
357                                    Register map,
358                                    Register hash,
359                                    Label* index_string,
360                                    Label* not_symbol) {
361   // The key is not a smi.
362   // Is it a string?
363   __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
364   __ b(ge, not_symbol);
365
366   // Is the string an array index, with cached numeric value?
367   __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
368   __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
369   __ b(eq, index_string);
370
371   // Is the string a symbol?
372   // map: key map
373   __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
374   STATIC_ASSERT(kSymbolTag != 0);
375   __ tst(hash, Operand(kIsSymbolMask));
376   __ b(eq, not_symbol);
377 }
378
379
380 // Defined in ic.cc.
381 Object* CallIC_Miss(Arguments args);
382
383 // The generated code does not accept smi keys.
384 // The generated code falls through if both probes miss.
385 void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
386                                                int argc,
387                                                Code::Kind kind,
388                                                Code::ExtraICState extra_state) {
389   // ----------- S t a t e -------------
390   //  -- r1    : receiver
391   //  -- r2    : name
392   // -----------------------------------
393   Label number, non_number, non_string, boolean, probe, miss;
394
395   // Probe the stub cache.
396   Code::Flags flags = Code::ComputeFlags(kind,
397                                          MONOMORPHIC,
398                                          extra_state,
399                                          NORMAL,
400                                          argc);
401   Isolate::Current()->stub_cache()->GenerateProbe(
402       masm, flags, r1, r2, r3, r4, r5, r6);
403
404   // If the stub cache probing failed, the receiver might be a value.
405   // For value objects, we use the map of the prototype objects for
406   // the corresponding JSValue for the cache and that is what we need
407   // to probe.
408   //
409   // Check for number.
410   __ JumpIfSmi(r1, &number);
411   __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
412   __ b(ne, &non_number);
413   __ bind(&number);
414   StubCompiler::GenerateLoadGlobalFunctionPrototype(
415       masm, Context::NUMBER_FUNCTION_INDEX, r1);
416   __ b(&probe);
417
418   // Check for string.
419   __ bind(&non_number);
420   __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
421   __ b(hs, &non_string);
422   StubCompiler::GenerateLoadGlobalFunctionPrototype(
423       masm, Context::STRING_FUNCTION_INDEX, r1);
424   __ b(&probe);
425
426   // Check for boolean.
427   __ bind(&non_string);
428   __ LoadRoot(ip, Heap::kTrueValueRootIndex);
429   __ cmp(r1, ip);
430   __ b(eq, &boolean);
431   __ LoadRoot(ip, Heap::kFalseValueRootIndex);
432   __ cmp(r1, ip);
433   __ b(ne, &miss);
434   __ bind(&boolean);
435   StubCompiler::GenerateLoadGlobalFunctionPrototype(
436       masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
437
438   // Probe the stub cache for the value object.
439   __ bind(&probe);
440   Isolate::Current()->stub_cache()->GenerateProbe(
441       masm, flags, r1, r2, r3, r4, r5, r6);
442
443   __ bind(&miss);
444 }
445
446
447 static void GenerateFunctionTailCall(MacroAssembler* masm,
448                                      int argc,
449                                      Label* miss,
450                                      Register scratch) {
451   // r1: function
452
453   // Check that the value isn't a smi.
454   __ JumpIfSmi(r1, miss);
455
456   // Check that the value is a JSFunction.
457   __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
458   __ b(ne, miss);
459
460   // Invoke the function.
461   ParameterCount actual(argc);
462   __ InvokeFunction(r1, actual, JUMP_FUNCTION,
463                     NullCallWrapper(), CALL_AS_METHOD);
464 }
465
466
467 void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
468   // ----------- S t a t e -------------
469   //  -- r2    : name
470   //  -- lr    : return address
471   // -----------------------------------
472   Label miss;
473
474   // Get the receiver of the function from the stack into r1.
475   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
476
477   GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
478
479   // r0: elements
480   // Search the dictionary - put result in register r1.
481   GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
482
483   GenerateFunctionTailCall(masm, argc, &miss, r4);
484
485   __ bind(&miss);
486 }
487
488
489 void CallICBase::GenerateMiss(MacroAssembler* masm,
490                               int argc,
491                               IC::UtilityId id,
492                               Code::ExtraICState extra_state) {
493   // ----------- S t a t e -------------
494   //  -- r2    : name
495   //  -- lr    : return address
496   // -----------------------------------
497   Isolate* isolate = masm->isolate();
498
499   if (id == IC::kCallIC_Miss) {
500     __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4);
501   } else {
502     __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4);
503   }
504
505   // Get the receiver of the function from the stack.
506   __ ldr(r3, MemOperand(sp, argc * kPointerSize));
507
508   {
509     FrameScope scope(masm, StackFrame::INTERNAL);
510
511     // Push the receiver and the name of the function.
512     __ Push(r3, r2);
513
514     // Call the entry.
515     __ mov(r0, Operand(2));
516     __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
517
518     CEntryStub stub(1);
519     __ CallStub(&stub);
520
521     // Move result to r1 and leave the internal frame.
522     __ mov(r1, Operand(r0));
523   }
524
525   // Check if the receiver is a global object of some sort.
526   // This can happen only for regular CallIC but not KeyedCallIC.
527   if (id == IC::kCallIC_Miss) {
528     Label invoke, global;
529     __ ldr(r2, MemOperand(sp, argc * kPointerSize));  // receiver
530     __ JumpIfSmi(r2, &invoke);
531     __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
532     __ b(eq, &global);
533     __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
534     __ b(ne, &invoke);
535
536     // Patch the receiver on the stack.
537     __ bind(&global);
538     __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
539     __ str(r2, MemOperand(sp, argc * kPointerSize));
540     __ bind(&invoke);
541   }
542
543   // Invoke the function.
544   CallKind call_kind = CallICBase::Contextual::decode(extra_state)
545       ? CALL_AS_FUNCTION
546       : CALL_AS_METHOD;
547   ParameterCount actual(argc);
548   __ InvokeFunction(r1,
549                     actual,
550                     JUMP_FUNCTION,
551                     NullCallWrapper(),
552                     call_kind);
553 }
554
555
556 void CallIC::GenerateMegamorphic(MacroAssembler* masm,
557                                  int argc,
558                                  Code::ExtraICState extra_ic_state) {
559   // ----------- S t a t e -------------
560   //  -- r2    : name
561   //  -- lr    : return address
562   // -----------------------------------
563
564   // Get the receiver of the function from the stack into r1.
565   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
566   GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
567   GenerateMiss(masm, argc, extra_ic_state);
568 }
569
570
571 void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
572   // ----------- S t a t e -------------
573   //  -- r2    : name
574   //  -- lr    : return address
575   // -----------------------------------
576
577   // Get the receiver of the function from the stack into r1.
578   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
579
580   Label do_call, slow_call, slow_load, slow_reload_receiver;
581   Label check_number_dictionary, check_string, lookup_monomorphic_cache;
582   Label index_smi, index_string;
583
584   // Check that the key is a smi.
585   __ JumpIfNotSmi(r2, &check_string);
586   __ bind(&index_smi);
587   // Now the key is known to be a smi. This place is also jumped to from below
588   // where a numeric string is converted to a smi.
589
590   GenerateKeyedLoadReceiverCheck(
591       masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
592
593   GenerateFastArrayLoad(
594       masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
595   Counters* counters = masm->isolate()->counters();
596   __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
597
598   __ bind(&do_call);
599   // receiver in r1 is not used after this point.
600   // r2: key
601   // r1: function
602   GenerateFunctionTailCall(masm, argc, &slow_call, r0);
603
604   __ bind(&check_number_dictionary);
605   // r2: key
606   // r3: elements map
607   // r4: elements
608   // Check whether the elements is a number dictionary.
609   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
610   __ cmp(r3, ip);
611   __ b(ne, &slow_load);
612   __ mov(r0, Operand(r2, ASR, kSmiTagSize));
613   // r0: untagged index
614   __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5);
615   __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
616   __ jmp(&do_call);
617
618   __ bind(&slow_load);
619   // This branch is taken when calling KeyedCallIC_Miss is neither required
620   // nor beneficial.
621   __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
622   {
623     FrameScope scope(masm, StackFrame::INTERNAL);
624     __ push(r2);  // save the key
625     __ Push(r1, r2);  // pass the receiver and the key
626     __ CallRuntime(Runtime::kKeyedGetProperty, 2);
627     __ pop(r2);  // restore the key
628   }
629   __ mov(r1, r0);
630   __ jmp(&do_call);
631
632   __ bind(&check_string);
633   GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
634
635   // The key is known to be a symbol.
636   // If the receiver is a regular JS object with slow properties then do
637   // a quick inline probe of the receiver's dictionary.
638   // Otherwise do the monomorphic cache probe.
639   GenerateKeyedLoadReceiverCheck(
640       masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
641
642   __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
643   __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
644   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
645   __ cmp(r3, ip);
646   __ b(ne, &lookup_monomorphic_cache);
647
648   GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
649   __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
650   __ jmp(&do_call);
651
652   __ bind(&lookup_monomorphic_cache);
653   __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
654   GenerateMonomorphicCacheProbe(masm,
655                                 argc,
656                                 Code::KEYED_CALL_IC,
657                                 Code::kNoExtraICState);
658   // Fall through on miss.
659
660   __ bind(&slow_call);
661   // This branch is taken if:
662   // - the receiver requires boxing or access check,
663   // - the key is neither smi nor symbol,
664   // - the value loaded is not a function,
665   // - there is hope that the runtime will create a monomorphic call stub
666   //   that will get fetched next time.
667   __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
668   GenerateMiss(masm, argc);
669
670   __ bind(&index_string);
671   __ IndexFromHash(r3, r2);
672   // Now jump to the place where smi keys are handled.
673   __ jmp(&index_smi);
674 }
675
676
677 void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
678   // ----------- S t a t e -------------
679   //  -- r2    : name
680   //  -- lr    : return address
681   // -----------------------------------
682
683   // Check if the name is a string.
684   Label miss;
685   __ JumpIfSmi(r2, &miss);
686   __ IsObjectJSStringType(r2, r0, &miss);
687
688   CallICBase::GenerateNormal(masm, argc);
689   __ bind(&miss);
690   GenerateMiss(masm, argc);
691 }
692
693
694 // Defined in ic.cc.
695 Object* LoadIC_Miss(Arguments args);
696
697 void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
698   // ----------- S t a t e -------------
699   //  -- r2    : name
700   //  -- lr    : return address
701   //  -- r0    : receiver
702   //  -- sp[0] : receiver
703   // -----------------------------------
704
705   // Probe the stub cache.
706   Code::Flags flags =
707       Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
708   Isolate::Current()->stub_cache()->GenerateProbe(
709       masm, flags, r0, r2, r3, r4, r5, r6);
710
711   // Cache miss: Jump to runtime.
712   GenerateMiss(masm);
713 }
714
715
716 void LoadIC::GenerateNormal(MacroAssembler* masm) {
717   // ----------- S t a t e -------------
718   //  -- r2    : name
719   //  -- lr    : return address
720   //  -- r0    : receiver
721   //  -- sp[0] : receiver
722   // -----------------------------------
723   Label miss;
724
725   GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
726
727   // r1: elements
728   GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
729   __ Ret();
730
731   // Cache miss: Jump to runtime.
732   __ bind(&miss);
733   GenerateMiss(masm);
734 }
735
736
737 void LoadIC::GenerateMiss(MacroAssembler* masm) {
738   // ----------- S t a t e -------------
739   //  -- r2    : name
740   //  -- lr    : return address
741   //  -- r0    : receiver
742   //  -- sp[0] : receiver
743   // -----------------------------------
744   Isolate* isolate = masm->isolate();
745
746   __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
747
748   __ mov(r3, r0);
749   __ Push(r3, r2);
750
751   // Perform tail call to the entry.
752   ExternalReference ref =
753       ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
754   __ TailCallExternalReference(ref, 2, 1);
755 }
756
757
758 static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
759                                                 Register object,
760                                                 Register key,
761                                                 Register scratch1,
762                                                 Register scratch2,
763                                                 Register scratch3,
764                                                 Label* unmapped_case,
765                                                 Label* slow_case) {
766   Heap* heap = masm->isolate()->heap();
767
768   // Check that the receiver is a JSObject. Because of the map check
769   // later, we do not need to check for interceptors or whether it
770   // requires access checks.
771   __ JumpIfSmi(object, slow_case);
772   // Check that the object is some kind of JSObject.
773   __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE);
774   __ b(lt, slow_case);
775
776   // Check that the key is a positive smi.
777   __ tst(key, Operand(0x8000001));
778   __ b(ne, slow_case);
779
780   // Load the elements into scratch1 and check its map.
781   Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
782   __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
783   __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
784
785   // Check if element is in the range of mapped arguments. If not, jump
786   // to the unmapped lookup with the parameter map in scratch1.
787   __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
788   __ sub(scratch2, scratch2, Operand(Smi::FromInt(2)));
789   __ cmp(key, Operand(scratch2));
790   __ b(cs, unmapped_case);
791
792   // Load element index and check whether it is the hole.
793   const int kOffset =
794       FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
795
796   __ mov(scratch3, Operand(kPointerSize >> 1));
797   __ mul(scratch3, key, scratch3);
798   __ add(scratch3, scratch3, Operand(kOffset));
799
800   __ ldr(scratch2, MemOperand(scratch1, scratch3));
801   __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
802   __ cmp(scratch2, scratch3);
803   __ b(eq, unmapped_case);
804
805   // Load value from context and return it. We can reuse scratch1 because
806   // we do not jump to the unmapped lookup (which requires the parameter
807   // map in scratch1).
808   __ ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
809   __ mov(scratch3, Operand(kPointerSize >> 1));
810   __ mul(scratch3, scratch2, scratch3);
811   __ add(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
812   return MemOperand(scratch1, scratch3);
813 }
814
815
816 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
817                                                   Register key,
818                                                   Register parameter_map,
819                                                   Register scratch,
820                                                   Label* slow_case) {
821   // Element is in arguments backing store, which is referenced by the
822   // second element of the parameter_map. The parameter_map register
823   // must be loaded with the parameter map of the arguments object and is
824   // overwritten.
825   const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
826   Register backing_store = parameter_map;
827   __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
828   Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
829   __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
830               DONT_DO_SMI_CHECK);
831   __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
832   __ cmp(key, Operand(scratch));
833   __ b(cs, slow_case);
834   __ mov(scratch, Operand(kPointerSize >> 1));
835   __ mul(scratch, key, scratch);
836   __ add(scratch,
837          scratch,
838          Operand(FixedArray::kHeaderSize - kHeapObjectTag));
839   return MemOperand(backing_store, scratch);
840 }
841
842
843 void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
844   // ---------- S t a t e --------------
845   //  -- lr     : return address
846   //  -- r0     : key
847   //  -- r1     : receiver
848   // -----------------------------------
849   Label slow, notin;
850   MemOperand mapped_location =
851       GenerateMappedArgumentsLookup(masm, r1, r0, r2, r3, r4, &notin, &slow);
852   __ ldr(r0, mapped_location);
853   __ Ret();
854   __ bind(&notin);
855   // The unmapped lookup expects that the parameter map is in r2.
856   MemOperand unmapped_location =
857       GenerateUnmappedArgumentsLookup(masm, r0, r2, r3, &slow);
858   __ ldr(r2, unmapped_location);
859   __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
860   __ cmp(r2, r3);
861   __ b(eq, &slow);
862   __ mov(r0, r2);
863   __ Ret();
864   __ bind(&slow);
865   GenerateMiss(masm, false);
866 }
867
868
869 void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
870   // ---------- S t a t e --------------
871   //  -- r0     : value
872   //  -- r1     : key
873   //  -- r2     : receiver
874   //  -- lr     : return address
875   // -----------------------------------
876   Label slow, notin;
877   MemOperand mapped_location =
878       GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, &notin, &slow);
879   __ str(r0, mapped_location);
880   __ add(r6, r3, r5);
881   __ mov(r9, r0);
882   __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
883   __ Ret();
884   __ bind(&notin);
885   // The unmapped lookup expects that the parameter map is in r3.
886   MemOperand unmapped_location =
887       GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
888   __ str(r0, unmapped_location);
889   __ add(r6, r3, r4);
890   __ mov(r9, r0);
891   __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
892   __ Ret();
893   __ bind(&slow);
894   GenerateMiss(masm, false);
895 }
896
897
898 void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
899                                              int argc) {
900   // ----------- S t a t e -------------
901   //  -- r2    : name
902   //  -- lr    : return address
903   // -----------------------------------
904   Label slow, notin;
905   // Load receiver.
906   __ ldr(r1, MemOperand(sp, argc * kPointerSize));
907   MemOperand mapped_location =
908       GenerateMappedArgumentsLookup(masm, r1, r2, r3, r4, r5, &notin, &slow);
909   __ ldr(r1, mapped_location);
910   GenerateFunctionTailCall(masm, argc, &slow, r3);
911   __ bind(&notin);
912   // The unmapped lookup expects that the parameter map is in r3.
913   MemOperand unmapped_location =
914       GenerateUnmappedArgumentsLookup(masm, r2, r3, r4, &slow);
915   __ ldr(r1, unmapped_location);
916   __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
917   __ cmp(r1, r3);
918   __ b(eq, &slow);
919   GenerateFunctionTailCall(masm, argc, &slow, r3);
920   __ bind(&slow);
921   GenerateMiss(masm, argc);
922 }
923
924
925 Object* KeyedLoadIC_Miss(Arguments args);
926
927
928 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
929   // ---------- S t a t e --------------
930   //  -- lr     : return address
931   //  -- r0     : key
932   //  -- r1     : receiver
933   // -----------------------------------
934   Isolate* isolate = masm->isolate();
935
936   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
937
938   __ Push(r1, r0);
939
940   // Perform tail call to the entry.
941   ExternalReference ref = force_generic
942       ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
943       : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
944
945   __ TailCallExternalReference(ref, 2, 1);
946 }
947
948
949 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
950   // ---------- S t a t e --------------
951   //  -- lr     : return address
952   //  -- r0     : key
953   //  -- r1     : receiver
954   // -----------------------------------
955
956   __ Push(r1, r0);
957
958   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
959 }
960
961
962 void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
963   // ---------- S t a t e --------------
964   //  -- lr     : return address
965   //  -- r0     : key
966   //  -- r1     : receiver
967   // -----------------------------------
968   Label slow, check_string, index_smi, index_string, property_array_property;
969   Label probe_dictionary, check_number_dictionary;
970
971   Register key = r0;
972   Register receiver = r1;
973
974   Isolate* isolate = masm->isolate();
975
976   // Check that the key is a smi.
977   __ JumpIfNotSmi(key, &check_string);
978   __ bind(&index_smi);
979   // Now the key is known to be a smi. This place is also jumped to from below
980   // where a numeric string is converted to a smi.
981
982   GenerateKeyedLoadReceiverCheck(
983       masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
984
985   // Check the receiver's map to see if it has fast elements.
986   __ CheckFastElements(r2, r3, &check_number_dictionary);
987
988   GenerateFastArrayLoad(
989       masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
990   __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
991   __ Ret();
992
993   __ bind(&check_number_dictionary);
994   __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
995   __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
996
997   // Check whether the elements is a number dictionary.
998   // r0: key
999   // r3: elements map
1000   // r4: elements
1001   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1002   __ cmp(r3, ip);
1003   __ b(ne, &slow);
1004   __ mov(r2, Operand(r0, ASR, kSmiTagSize));
1005   __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5);
1006   __ Ret();
1007
1008   // Slow case, key and receiver still in r0 and r1.
1009   __ bind(&slow);
1010   __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
1011                       1, r2, r3);
1012   GenerateRuntimeGetProperty(masm);
1013
1014   __ bind(&check_string);
1015   GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
1016
1017   GenerateKeyedLoadReceiverCheck(
1018       masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1019
1020   // If the receiver is a fast-case object, check the keyed lookup
1021   // cache. Otherwise probe the dictionary.
1022   __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1023   __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
1024   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1025   __ cmp(r4, ip);
1026   __ b(eq, &probe_dictionary);
1027
1028   // Load the map of the receiver, compute the keyed lookup cache hash
1029   // based on 32 bits of the map pointer and the string hash.
1030   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1031   __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1032   __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1033   __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
1034   int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
1035   __ And(r3, r3, Operand(mask));
1036
1037   // Load the key (consisting of map and symbol) from the cache and
1038   // check for match.
1039   Label load_in_object_property;
1040   static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
1041   Label hit_on_nth_entry[kEntriesPerBucket];
1042   ExternalReference cache_keys =
1043       ExternalReference::keyed_lookup_cache_keys(isolate);
1044
1045   __ mov(r4, Operand(cache_keys));
1046   __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1047
1048   for (int i = 0; i < kEntriesPerBucket - 1; i++) {
1049     Label try_next_entry;
1050     // Load map and move r4 to next entry.
1051     __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex));
1052     __ cmp(r2, r5);
1053     __ b(ne, &try_next_entry);
1054     __ ldr(r5, MemOperand(r4, -kPointerSize));  // Load symbol
1055     __ cmp(r0, r5);
1056     __ b(eq, &hit_on_nth_entry[i]);
1057     __ bind(&try_next_entry);
1058   }
1059
1060   // Last entry: Load map and move r4 to symbol.
1061   __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));
1062   __ cmp(r2, r5);
1063   __ b(ne, &slow);
1064   __ ldr(r5, MemOperand(r4));
1065   __ cmp(r0, r5);
1066   __ b(ne, &slow);
1067
1068   // Get field offset.
1069   // r0     : key
1070   // r1     : receiver
1071   // r2     : receiver's map
1072   // r3     : lookup cache index
1073   ExternalReference cache_field_offsets =
1074       ExternalReference::keyed_lookup_cache_field_offsets(isolate);
1075
1076   // Hit on nth entry.
1077   for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
1078     __ bind(&hit_on_nth_entry[i]);
1079     __ mov(r4, Operand(cache_field_offsets));
1080     if (i != 0) {
1081       __ add(r3, r3, Operand(i));
1082     }
1083     __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1084     __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
1085     __ sub(r5, r5, r6, SetCC);
1086     __ b(ge, &property_array_property);
1087     if (i != 0) {
1088       __ jmp(&load_in_object_property);
1089     }
1090   }
1091
1092   // Load in-object property.
1093   __ bind(&load_in_object_property);
1094   __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1095   __ add(r6, r6, r5);  // Index from start of object.
1096   __ sub(r1, r1, Operand(kHeapObjectTag));  // Remove the heap tag.
1097   __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1098   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1099                       1, r2, r3);
1100   __ Ret();
1101
1102   // Load property array property.
1103   __ bind(&property_array_property);
1104   __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1105   __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1106   __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
1107   __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1108                       1, r2, r3);
1109   __ Ret();
1110
1111   // Do a quick inline probe of the receiver's dictionary, if it
1112   // exists.
1113   __ bind(&probe_dictionary);
1114   // r1: receiver
1115   // r0: key
1116   // r3: elements
1117   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1118   __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1119   GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
1120   // Load the property to r0.
1121   GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
1122   __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1123                       1, r2, r3);
1124   __ Ret();
1125
1126   __ bind(&index_string);
1127   __ IndexFromHash(r3, key);
1128   // Now jump to the place where smi keys are handled.
1129   __ jmp(&index_smi);
1130 }
1131
1132
1133 void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1134   // ---------- S t a t e --------------
1135   //  -- lr     : return address
1136   //  -- r0     : key (index)
1137   //  -- r1     : receiver
1138   // -----------------------------------
1139   Label miss;
1140
1141   Register receiver = r1;
1142   Register index = r0;
1143   Register scratch = r3;
1144   Register result = r0;
1145
1146   StringCharAtGenerator char_at_generator(receiver,
1147                                           index,
1148                                           scratch,
1149                                           result,
1150                                           &miss,  // When not a string.
1151                                           &miss,  // When not a number.
1152                                           &miss,  // When index out of range.
1153                                           STRING_INDEX_IS_ARRAY_INDEX);
1154   char_at_generator.GenerateFast(masm);
1155   __ Ret();
1156
1157   StubRuntimeCallHelper call_helper;
1158   char_at_generator.GenerateSlow(masm, call_helper);
1159
1160   __ bind(&miss);
1161   GenerateMiss(masm, false);
1162 }
1163
1164
1165 void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1166   // ---------- S t a t e --------------
1167   //  -- lr     : return address
1168   //  -- r0     : key
1169   //  -- r1     : receiver
1170   // -----------------------------------
1171   Label slow;
1172
1173   // Check that the receiver isn't a smi.
1174   __ JumpIfSmi(r1, &slow);
1175
1176   // Check that the key is an array index, that is Uint32.
1177   __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1178   __ b(ne, &slow);
1179
1180   // Get the map of the receiver.
1181   __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1182
1183   // Check that it has indexed interceptor and access checks
1184   // are not enabled for this object.
1185   __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1186   __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1187   __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1188   __ b(ne, &slow);
1189
1190   // Everything is fine, call runtime.
1191   __ Push(r1, r0);  // Receiver, key.
1192
1193   // Perform tail call to the entry.
1194   __ TailCallExternalReference(
1195       ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
1196                         masm->isolate()),
1197       2,
1198       1);
1199
1200   __ bind(&slow);
1201   GenerateMiss(masm, false);
1202 }
1203
1204
1205 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1206   // ---------- S t a t e --------------
1207   //  -- r0     : value
1208   //  -- r1     : key
1209   //  -- r2     : receiver
1210   //  -- lr     : return address
1211   // -----------------------------------
1212
1213   // Push receiver, key and value for runtime call.
1214   __ Push(r2, r1, r0);
1215
1216   ExternalReference ref = force_generic
1217       ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1218                           masm->isolate())
1219       : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1220   __ TailCallExternalReference(ref, 3, 1);
1221 }
1222
1223
1224 void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1225   // ---------- S t a t e --------------
1226   //  -- r0     : value
1227   //  -- r1     : key
1228   //  -- r2     : receiver
1229   //  -- lr     : return address
1230   // -----------------------------------
1231
1232   // Push receiver, key and value for runtime call.
1233   __ Push(r2, r1, r0);
1234
1235   // The slow case calls into the runtime to complete the store without causing
1236   // an IC miss that would otherwise cause a transition to the generic stub.
1237   ExternalReference ref =
1238       ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1239   __ TailCallExternalReference(ref, 3, 1);
1240 }
1241
1242
1243 void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1244   // ---------- S t a t e --------------
1245   //  -- r2     : receiver
1246   //  -- r3     : target map
1247   //  -- lr     : return address
1248   // -----------------------------------
1249   // Must return the modified receiver in r0.
1250   if (!FLAG_trace_elements_transitions) {
1251     Label fail;
1252     ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
1253     __ mov(r0, r2);
1254     __ Ret();
1255     __ bind(&fail);
1256   }
1257
1258   __ push(r2);
1259   __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1260 }
1261
1262
1263 void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1264     MacroAssembler* masm) {
1265   // ---------- S t a t e --------------
1266   //  -- r2     : receiver
1267   //  -- r3     : target map
1268   //  -- lr     : return address
1269   // -----------------------------------
1270   // Must return the modified receiver in r0.
1271   if (!FLAG_trace_elements_transitions) {
1272     Label fail;
1273     ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
1274     __ mov(r0, r2);
1275     __ Ret();
1276     __ bind(&fail);
1277   }
1278
1279   __ push(r2);
1280   __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1281 }
1282
1283
1284 void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1285                                               StrictModeFlag strict_mode) {
1286   // ---------- S t a t e --------------
1287   //  -- r0     : value
1288   //  -- r1     : key
1289   //  -- r2     : receiver
1290   //  -- lr     : return address
1291   // -----------------------------------
1292
1293   // Push receiver, key and value for runtime call.
1294   __ Push(r2, r1, r0);
1295
1296   __ mov(r1, Operand(Smi::FromInt(NONE)));          // PropertyAttributes
1297   __ mov(r0, Operand(Smi::FromInt(strict_mode)));   // Strict mode.
1298   __ Push(r1, r0);
1299
1300   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1301 }
1302
1303
1304 void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1305                                    StrictModeFlag strict_mode) {
1306   // ---------- S t a t e --------------
1307   //  -- r0     : value
1308   //  -- r1     : key
1309   //  -- r2     : receiver
1310   //  -- lr     : return address
1311   // -----------------------------------
1312   Label slow, array, extra, check_if_double_array;
1313   Label fast_object_with_map_check, fast_object_without_map_check;
1314   Label fast_double_with_map_check, fast_double_without_map_check;
1315   Label transition_smi_elements, finish_object_store, non_double_value;
1316   Label transition_double_elements;
1317
1318   // Register usage.
1319   Register value = r0;
1320   Register key = r1;
1321   Register receiver = r2;
1322   Register receiver_map = r3;
1323   Register elements_map = r6;
1324   Register elements = r7;  // Elements array of the receiver.
1325   // r4 and r5 are used as general scratch registers.
1326
1327   // Check that the key is a smi.
1328   __ JumpIfNotSmi(key, &slow);
1329   // Check that the object isn't a smi.
1330   __ JumpIfSmi(receiver, &slow);
1331   // Get the map of the object.
1332   __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
1333   // Check that the receiver does not require access checks.  We need
1334   // to do this because this generic stub does not perform map checks.
1335   __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
1336   __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1337   __ b(ne, &slow);
1338   // Check if the object is a JS array or not.
1339   __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
1340   __ cmp(r4, Operand(JS_ARRAY_TYPE));
1341   __ b(eq, &array);
1342   // Check that the object is some kind of JSObject.
1343   __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
1344   __ b(lt, &slow);
1345
1346   // Object case: Check key against length in the elements array.
1347   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1348   // Check array bounds. Both the key and the length of FixedArray are smis.
1349   __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1350   __ cmp(key, Operand(ip));
1351   __ b(lo, &fast_object_with_map_check);
1352
1353   // Slow case, handle jump to runtime.
1354   __ bind(&slow);
1355   // Entry registers are intact.
1356   // r0: value.
1357   // r1: key.
1358   // r2: receiver.
1359   GenerateRuntimeSetProperty(masm, strict_mode);
1360
1361   // Extra capacity case: Check if there is extra capacity to
1362   // perform the store and update the length. Used for adding one
1363   // element to the array by writing to array[array.length].
1364   __ bind(&extra);
1365   // Condition code from comparing key and array length is still available.
1366   __ b(ne, &slow);  // Only support writing to writing to array[array.length].
1367   // Check for room in the elements backing store.
1368   // Both the key and the length of FixedArray are smis.
1369   __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
1370   __ cmp(key, Operand(ip));
1371   __ b(hs, &slow);
1372   __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1373   __ cmp(elements_map,
1374          Operand(masm->isolate()->factory()->fixed_array_map()));
1375   __ b(ne, &check_if_double_array);
1376   // Calculate key + 1 as smi.
1377   STATIC_ASSERT(kSmiTag == 0);
1378   __ add(r4, key, Operand(Smi::FromInt(1)));
1379   __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
1380   __ b(&fast_object_without_map_check);
1381
1382   __ bind(&check_if_double_array);
1383   __ cmp(elements_map,
1384          Operand(masm->isolate()->factory()->fixed_double_array_map()));
1385   __ b(ne, &slow);
1386   // Add 1 to key, and go to common element store code for doubles.
1387   STATIC_ASSERT(kSmiTag == 0);
1388   __ add(r4, key, Operand(Smi::FromInt(1)));
1389   __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
1390   __ jmp(&fast_double_without_map_check);
1391
1392   // Array case: Get the length and the elements array from the JS
1393   // array. Check that the array is in fast mode (and writable); if it
1394   // is the length is always a smi.
1395   __ bind(&array);
1396   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1397
1398   // Check the key against the length in the array.
1399   __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1400   __ cmp(key, Operand(ip));
1401   __ b(hs, &extra);
1402   // Fall through to fast case.
1403
1404   __ bind(&fast_object_with_map_check);
1405   Register scratch_value = r4;
1406   Register address = r5;
1407   __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1408   __ cmp(elements_map,
1409          Operand(masm->isolate()->factory()->fixed_array_map()));
1410   __ b(ne, &fast_double_with_map_check);
1411   __ bind(&fast_object_without_map_check);
1412   // Smi stores don't require further checks.
1413   Label non_smi_value;
1414   __ JumpIfNotSmi(value, &non_smi_value);
1415   // It's irrelevant whether array is smi-only or not when writing a smi.
1416   __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1417   __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1418   __ str(value, MemOperand(address));
1419   __ Ret();
1420
1421   __ bind(&non_smi_value);
1422   // Escape to elements kind transition case.
1423   __ CheckFastObjectElements(receiver_map, scratch_value,
1424                              &transition_smi_elements);
1425   // Fast elements array, store the value to the elements backing store.
1426   __ bind(&finish_object_store);
1427   __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1428   __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1429   __ str(value, MemOperand(address));
1430   // Update write barrier for the elements array address.
1431   __ mov(scratch_value, value);  // Preserve the value which is returned.
1432   __ RecordWrite(elements,
1433                  address,
1434                  scratch_value,
1435                  kLRHasNotBeenSaved,
1436                  kDontSaveFPRegs,
1437                  EMIT_REMEMBERED_SET,
1438                  OMIT_SMI_CHECK);
1439   __ Ret();
1440
1441   __ bind(&fast_double_with_map_check);
1442   // Check for fast double array case. If this fails, call through to the
1443   // runtime.
1444   __ cmp(elements_map,
1445          Operand(masm->isolate()->factory()->fixed_double_array_map()));
1446   __ b(ne, &slow);
1447   __ bind(&fast_double_without_map_check);
1448   __ StoreNumberToDoubleElements(value,
1449                                  key,
1450                                  receiver,
1451                                  elements,
1452                                  r3,
1453                                  r4,
1454                                  r5,
1455                                  r6,
1456                                  &transition_double_elements);
1457   __ Ret();
1458
1459   __ bind(&transition_smi_elements);
1460   // Transition the array appropriately depending on the value type.
1461   __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
1462   __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
1463   __ b(ne, &non_double_value);
1464
1465   // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
1466   // FAST_DOUBLE_ELEMENTS and complete the store.
1467   __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1468                                          FAST_DOUBLE_ELEMENTS,
1469                                          receiver_map,
1470                                          r4,
1471                                          &slow);
1472   ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
1473   ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
1474   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1475   __ jmp(&fast_double_without_map_check);
1476
1477   __ bind(&non_double_value);
1478   // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
1479   __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1480                                          FAST_ELEMENTS,
1481                                          receiver_map,
1482                                          r4,
1483                                          &slow);
1484   ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
1485   ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
1486   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1487   __ jmp(&finish_object_store);
1488
1489   __ bind(&transition_double_elements);
1490   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
1491   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
1492   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1493   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1494                                          FAST_ELEMENTS,
1495                                          receiver_map,
1496                                          r4,
1497                                          &slow);
1498   ASSERT(receiver_map.is(r3));  // Transition code expects map in r3
1499   ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
1500   __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1501   __ jmp(&finish_object_store);
1502 }
1503
1504
1505 void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1506                                   StrictModeFlag strict_mode) {
1507   // ----------- S t a t e -------------
1508   //  -- r0    : value
1509   //  -- r1    : receiver
1510   //  -- r2    : name
1511   //  -- lr    : return address
1512   // -----------------------------------
1513
1514   // Get the receiver from the stack and probe the stub cache.
1515   Code::Flags flags =
1516       Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
1517
1518   Isolate::Current()->stub_cache()->GenerateProbe(
1519       masm, flags, r1, r2, r3, r4, r5, r6);
1520
1521   // Cache miss: Jump to runtime.
1522   GenerateMiss(masm);
1523 }
1524
1525
1526 void StoreIC::GenerateMiss(MacroAssembler* masm) {
1527   // ----------- S t a t e -------------
1528   //  -- r0    : value
1529   //  -- r1    : receiver
1530   //  -- r2    : name
1531   //  -- lr    : return address
1532   // -----------------------------------
1533
1534   __ Push(r1, r2, r0);
1535
1536   // Perform tail call to the entry.
1537   ExternalReference ref =
1538       ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1539   __ TailCallExternalReference(ref, 3, 1);
1540 }
1541
1542
1543 void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1544   // ----------- S t a t e -------------
1545   //  -- r0    : value
1546   //  -- r1    : receiver
1547   //  -- r2    : name
1548   //  -- lr    : return address
1549   // -----------------------------------
1550   //
1551   // This accepts as a receiver anything JSArray::SetElementsLength accepts
1552   // (currently anything except for external arrays which means anything with
1553   // elements of FixedArray type).  Value must be a number, but only smis are
1554   // accepted as the most common case.
1555
1556   Label miss;
1557
1558   Register receiver = r1;
1559   Register value = r0;
1560   Register scratch = r3;
1561
1562   // Check that the receiver isn't a smi.
1563   __ JumpIfSmi(receiver, &miss);
1564
1565   // Check that the object is a JS array.
1566   __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1567   __ b(ne, &miss);
1568
1569   // Check that elements are FixedArray.
1570   // We rely on StoreIC_ArrayLength below to deal with all types of
1571   // fast elements (including COW).
1572   __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1573   __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1574   __ b(ne, &miss);
1575
1576   // Check that the array has fast properties, otherwise the length
1577   // property might have been redefined.
1578   __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
1579   __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
1580   __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
1581   __ b(eq, &miss);
1582
1583   // Check that value is a smi.
1584   __ JumpIfNotSmi(value, &miss);
1585
1586   // Prepare tail call to StoreIC_ArrayLength.
1587   __ Push(receiver, value);
1588
1589   ExternalReference ref =
1590       ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
1591   __ TailCallExternalReference(ref, 2, 1);
1592
1593   __ bind(&miss);
1594
1595   GenerateMiss(masm);
1596 }
1597
1598
1599 void StoreIC::GenerateNormal(MacroAssembler* masm) {
1600   // ----------- S t a t e -------------
1601   //  -- r0    : value
1602   //  -- r1    : receiver
1603   //  -- r2    : name
1604   //  -- lr    : return address
1605   // -----------------------------------
1606   Label miss;
1607
1608   GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1609
1610   GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
1611   Counters* counters = masm->isolate()->counters();
1612   __ IncrementCounter(counters->store_normal_hit(),
1613                       1, r4, r5);
1614   __ Ret();
1615
1616   __ bind(&miss);
1617   __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
1618   GenerateMiss(masm);
1619 }
1620
1621
1622 void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1623                                   StrictModeFlag strict_mode) {
1624   // ----------- S t a t e -------------
1625   //  -- r0    : value
1626   //  -- r1    : receiver
1627   //  -- r2    : name
1628   //  -- lr    : return address
1629   // -----------------------------------
1630
1631   __ Push(r1, r2, r0);
1632
1633   __ mov(r1, Operand(Smi::FromInt(NONE)));  // PropertyAttributes
1634   __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1635   __ Push(r1, r0);
1636
1637   // Do tail-call to runtime routine.
1638   __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1639 }
1640
1641
1642 #undef __
1643
1644
1645 Condition CompareIC::ComputeCondition(Token::Value op) {
1646   switch (op) {
1647     case Token::EQ_STRICT:
1648     case Token::EQ:
1649       return eq;
1650     case Token::LT:
1651       return lt;
1652     case Token::GT:
1653       return gt;
1654     case Token::LTE:
1655       return le;
1656     case Token::GTE:
1657       return ge;
1658     default:
1659       UNREACHABLE();
1660       return kNoCondition;
1661   }
1662 }
1663
1664
1665 void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1666   HandleScope scope;
1667   Handle<Code> rewritten;
1668   State previous_state = GetState();
1669   State state = TargetState(previous_state, false, x, y);
1670   if (state == GENERIC) {
1671     CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1672     rewritten = stub.GetCode();
1673   } else {
1674     ICCompareStub stub(op_, state);
1675     if (state == KNOWN_OBJECTS) {
1676       stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
1677     }
1678     rewritten = stub.GetCode();
1679   }
1680   set_target(*rewritten);
1681
1682 #ifdef DEBUG
1683   if (FLAG_trace_ic) {
1684     PrintF("[CompareIC (%s->%s)#%s]\n",
1685            GetStateName(previous_state),
1686            GetStateName(state),
1687            Token::Name(op_));
1688   }
1689 #endif
1690
1691   // Activate inlined smi code.
1692   if (previous_state == UNINITIALIZED) {
1693     PatchInlinedSmiCode(address());
1694   }
1695 }
1696
1697
1698 void PatchInlinedSmiCode(Address address) {
1699   Address cmp_instruction_address =
1700       address + Assembler::kCallTargetAddressOffset;
1701
1702   // If the instruction following the call is not a cmp rx, #yyy, nothing
1703   // was inlined.
1704   Instr instr = Assembler::instr_at(cmp_instruction_address);
1705   if (!Assembler::IsCmpImmediate(instr)) {
1706     return;
1707   }
1708
1709   // The delta to the start of the map check instruction and the
1710   // condition code uses at the patched jump.
1711   int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1712   delta +=
1713       Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1714   // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1715   // nothing was inlined.
1716   if (delta == 0) {
1717     return;
1718   }
1719
1720 #ifdef DEBUG
1721   if (FLAG_trace_ic) {
1722     PrintF("[  patching ic at %p, cmp=%p, delta=%d\n",
1723            address, cmp_instruction_address, delta);
1724   }
1725 #endif
1726
1727   Address patch_address =
1728       cmp_instruction_address - delta * Instruction::kInstrSize;
1729   Instr instr_at_patch = Assembler::instr_at(patch_address);
1730   Instr branch_instr =
1731       Assembler::instr_at(patch_address + Instruction::kInstrSize);
1732   ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1733   ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1734             Assembler::GetRm(instr_at_patch).code());
1735   ASSERT(Assembler::IsBranch(branch_instr));
1736   if (Assembler::GetCondition(branch_instr) == eq) {
1737     // This is patching a "jump if not smi" site to be active.
1738     // Changing
1739     //   cmp rx, rx
1740     //   b eq, <target>
1741     // to
1742     //   tst rx, #kSmiTagMask
1743     //   b ne, <target>
1744     CodePatcher patcher(patch_address, 2);
1745     Register reg = Assembler::GetRn(instr_at_patch);
1746     patcher.masm()->tst(reg, Operand(kSmiTagMask));
1747     patcher.EmitCondition(ne);
1748   } else {
1749     ASSERT(Assembler::GetCondition(branch_instr) == ne);
1750     // This is patching a "jump if smi" site to be active.
1751     // Changing
1752     //   cmp rx, rx
1753     //   b ne, <target>
1754     // to
1755     //   tst rx, #kSmiTagMask
1756     //   b eq, <target>
1757     CodePatcher patcher(patch_address, 2);
1758     Register reg = Assembler::GetRn(instr_at_patch);
1759     patcher.masm()->tst(reg, Operand(kSmiTagMask));
1760     patcher.EmitCondition(eq);
1761   }
1762 }
1763
1764
1765 } }  // namespace v8::internal
1766
1767 #endif  // V8_TARGET_ARCH_ARM