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