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