deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / ic / mips64 / ic-mips64.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5
6 #include "src/v8.h"
7
8 #if V8_TARGET_ARCH_MIPS64
9
10 #include "src/codegen.h"
11 #include "src/ic/ic.h"
12 #include "src/ic/ic-compiler.h"
13 #include "src/ic/stub-cache.h"
14
15 namespace v8 {
16 namespace internal {
17
18
19 // ----------------------------------------------------------------------------
20 // Static IC stub generators.
21 //
22
23 #define __ ACCESS_MASM(masm)
24
25
26 static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm, Register type,
27                                             Label* global_object) {
28   // Register usage:
29   //   type: holds the receiver instance type on entry.
30   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_OBJECT_TYPE));
31   __ Branch(global_object, eq, type, Operand(JS_BUILTINS_OBJECT_TYPE));
32   __ Branch(global_object, eq, type, Operand(JS_GLOBAL_PROXY_TYPE));
33 }
34
35
36 // Helper function used from LoadIC GenerateNormal.
37 //
38 // elements: Property dictionary. It is not clobbered if a jump to the miss
39 //           label is done.
40 // name:     Property name. It is not clobbered if a jump to the miss label is
41 //           done
42 // result:   Register for the result. It is only updated if a jump to the miss
43 //           label is not done. Can be the same as elements or name clobbering
44 //           one of these in the case of not jumping to the miss label.
45 // The two scratch registers need to be different from elements, name and
46 // result.
47 // The generated code assumes that the receiver has slow properties,
48 // is not a global object and does not have interceptors.
49 // The address returned from GenerateStringDictionaryProbes() in scratch2
50 // is used.
51 static void GenerateDictionaryLoad(MacroAssembler* masm, Label* miss,
52                                    Register elements, Register name,
53                                    Register result, Register scratch1,
54                                    Register scratch2) {
55   // Main use of the scratch registers.
56   // scratch1: Used as temporary and to hold the capacity of the property
57   //           dictionary.
58   // scratch2: Used as temporary.
59   Label done;
60
61   // Probe the dictionary.
62   NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
63                                                    name, scratch1, scratch2);
64
65   // If probing finds an entry check that the value is a normal
66   // property.
67   __ bind(&done);  // scratch2 == elements + 4 * index.
68   const int kElementsStartOffset =
69       NameDictionary::kHeaderSize +
70       NameDictionary::kElementsStartIndex * kPointerSize;
71   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
72   __ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
73   __ And(at, scratch1,
74          Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
75   __ Branch(miss, ne, at, Operand(zero_reg));
76
77   // Get the value at the masked, scaled index and return.
78   __ ld(result,
79         FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
80 }
81
82
83 // Helper function used from StoreIC::GenerateNormal.
84 //
85 // elements: Property dictionary. It is not clobbered if a jump to the miss
86 //           label is done.
87 // name:     Property name. It is not clobbered if a jump to the miss label is
88 //           done
89 // value:    The value to store.
90 // The two scratch registers need to be different from elements, name and
91 // result.
92 // The generated code assumes that the receiver has slow properties,
93 // is not a global object and does not have interceptors.
94 // The address returned from GenerateStringDictionaryProbes() in scratch2
95 // is used.
96 static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss,
97                                     Register elements, Register name,
98                                     Register value, Register scratch1,
99                                     Register scratch2) {
100   // Main use of the scratch registers.
101   // scratch1: Used as temporary and to hold the capacity of the property
102   //           dictionary.
103   // scratch2: Used as temporary.
104   Label done;
105
106   // Probe the dictionary.
107   NameDictionaryLookupStub::GeneratePositiveLookup(masm, miss, &done, elements,
108                                                    name, scratch1, scratch2);
109
110   // If probing finds an entry in the dictionary check that the value
111   // is a normal property that is not read only.
112   __ bind(&done);  // scratch2 == elements + 4 * index.
113   const int kElementsStartOffset =
114       NameDictionary::kHeaderSize +
115       NameDictionary::kElementsStartIndex * kPointerSize;
116   const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
117   const int kTypeAndReadOnlyMask =
118       (PropertyDetails::TypeField::kMask |
119        PropertyDetails::AttributesField::encode(READ_ONLY));
120   __ ld(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
121   __ And(at, scratch1, Operand(Smi::FromInt(kTypeAndReadOnlyMask)));
122   __ Branch(miss, ne, at, Operand(zero_reg));
123
124   // Store the value at the masked, scaled index and return.
125   const int kValueOffset = kElementsStartOffset + kPointerSize;
126   __ Daddu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
127   __ sd(value, MemOperand(scratch2));
128
129   // Update the write barrier. Make sure not to clobber the value.
130   __ mov(scratch1, value);
131   __ RecordWrite(elements, scratch2, scratch1, kRAHasNotBeenSaved,
132                  kDontSaveFPRegs);
133 }
134
135
136 // Checks the receiver for special cases (value type, slow case bits).
137 // Falls through for regular JS object.
138 static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
139                                            Register receiver, Register map,
140                                            Register scratch,
141                                            int interceptor_bit, Label* slow) {
142   // Check that the object isn't a smi.
143   __ JumpIfSmi(receiver, slow);
144   // Get the map of the receiver.
145   __ ld(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
146   // Check bit field.
147   __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
148   __ And(at, scratch,
149          Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
150   __ Branch(slow, ne, at, Operand(zero_reg));
151   // Check that the object is some kind of JS object EXCEPT JS Value type.
152   // In the case that the object is a value-wrapper object,
153   // we enter the runtime system to make sure that indexing into string
154   // objects work as intended.
155   DCHECK(JS_OBJECT_TYPE > JS_VALUE_TYPE);
156   __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
157   __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
158 }
159
160
161 // Loads an indexed element from a fast case array.
162 static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
163                                   Register key, Register elements,
164                                   Register scratch1, Register scratch2,
165                                   Register result, Label* slow) {
166   // Register use:
167   //
168   // receiver - holds the receiver on entry.
169   //            Unchanged unless 'result' is the same register.
170   //
171   // key      - holds the smi key on entry.
172   //            Unchanged unless 'result' is the same register.
173   //
174   // result   - holds the result on exit if the load succeeded.
175   //            Allowed to be the the same as 'receiver' or 'key'.
176   //            Unchanged on bailout so 'receiver' and 'key' can be safely
177   //            used by further computation.
178   //
179   // Scratch registers:
180   //
181   // elements - holds the elements of the receiver and its prototypes.
182   //
183   // scratch1 - used to hold elements length, bit fields, base addresses.
184   //
185   // scratch2 - used to hold maps, prototypes, and the loaded value.
186   Label check_prototypes, check_next_prototype;
187   Label done, in_bounds, return_undefined;
188
189   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
190   __ AssertFastElements(elements);
191
192   // Check that the key (index) is within bounds.
193   __ ld(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
194   __ Branch(&in_bounds, lo, key, Operand(scratch1));
195   // Out-of-bounds. Check the prototype chain to see if we can just return
196   // 'undefined'.
197   // Negative keys can't take the fast OOB path.
198   __ Branch(slow, lt, key, Operand(zero_reg));
199   __ bind(&check_prototypes);
200   __ ld(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
201   __ bind(&check_next_prototype);
202   __ ld(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset));
203   // scratch2: current prototype
204   __ LoadRoot(at, Heap::kNullValueRootIndex);
205   __ Branch(&return_undefined, eq, scratch2, Operand(at));
206   __ ld(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset));
207   __ ld(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset));
208   // elements: elements of current prototype
209   // scratch2: map of current prototype
210   __ lbu(scratch1, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
211   __ Branch(slow, lo, scratch1, Operand(JS_OBJECT_TYPE));
212   __ lbu(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset));
213   __ And(at, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) |
214                                (1 << Map::kHasIndexedInterceptor)));
215   __ Branch(slow, ne, at, Operand(zero_reg));
216   __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex);
217   __ Branch(slow, ne, elements, Operand(at));
218   __ Branch(&check_next_prototype);
219
220   __ bind(&return_undefined);
221   __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
222   __ Branch(&done);
223
224   __ bind(&in_bounds);
225   // Fast case: Do the load.
226   __ Daddu(scratch1, elements,
227            Operand(FixedArray::kHeaderSize - kHeapObjectTag));
228   // The key is a smi.
229   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
230   __ SmiScale(at, key, kPointerSizeLog2);
231   __ daddu(at, at, scratch1);
232   __ ld(scratch2, MemOperand(at));
233
234   __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
235   // In case the loaded value is the_hole we have to check the prototype chain.
236   __ Branch(&check_prototypes, eq, scratch2, Operand(at));
237   __ Move(result, scratch2);
238   __ bind(&done);
239 }
240
241
242 // Checks whether a key is an array index string or a unique name.
243 // Falls through if a key is a unique name.
244 static void GenerateKeyNameCheck(MacroAssembler* masm, Register key,
245                                  Register map, Register hash,
246                                  Label* index_string, Label* not_unique) {
247   // The key is not a smi.
248   Label unique;
249   // Is it a name?
250   __ GetObjectType(key, map, hash);
251   __ Branch(not_unique, hi, hash, Operand(LAST_UNIQUE_NAME_TYPE));
252   STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
253   __ Branch(&unique, eq, hash, Operand(LAST_UNIQUE_NAME_TYPE));
254
255   // Is the string an array index, with cached numeric value?
256   __ lwu(hash, FieldMemOperand(key, Name::kHashFieldOffset));
257   __ And(at, hash, Operand(Name::kContainsCachedArrayIndexMask));
258   __ Branch(index_string, eq, at, Operand(zero_reg));
259
260   // Is the string internalized? We know it's a string, so a single
261   // bit test is enough.
262   // map: key map
263   __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
264   STATIC_ASSERT(kInternalizedTag == 0);
265   __ And(at, hash, Operand(kIsNotInternalizedMask));
266   __ Branch(not_unique, ne, at, Operand(zero_reg));
267
268   __ bind(&unique);
269 }
270
271
272 void LoadIC::GenerateNormal(MacroAssembler* masm) {
273   Register dictionary = a0;
274   DCHECK(!dictionary.is(LoadDescriptor::ReceiverRegister()));
275   DCHECK(!dictionary.is(LoadDescriptor::NameRegister()));
276   Label slow;
277
278   __ ld(dictionary, FieldMemOperand(LoadDescriptor::ReceiverRegister(),
279                                     JSObject::kPropertiesOffset));
280   GenerateDictionaryLoad(masm, &slow, dictionary,
281                          LoadDescriptor::NameRegister(), v0, a3, a4);
282   __ Ret();
283
284   // Dictionary load failed, go slow (but don't miss).
285   __ bind(&slow);
286   GenerateRuntimeGetProperty(masm);
287 }
288
289
290 // A register that isn't one of the parameters to the load ic.
291 static const Register LoadIC_TempRegister() { return a3; }
292
293
294 static void LoadIC_PushArgs(MacroAssembler* masm) {
295   Register receiver = LoadDescriptor::ReceiverRegister();
296   Register name = LoadDescriptor::NameRegister();
297   if (FLAG_vector_ics) {
298     Register slot = VectorLoadICDescriptor::SlotRegister();
299     Register vector = VectorLoadICDescriptor::VectorRegister();
300
301     __ Push(receiver, name, slot, vector);
302   } else {
303     __ Push(receiver, name);
304   }
305 }
306
307
308 void LoadIC::GenerateMiss(MacroAssembler* masm) {
309   // The return address is on the stack.
310   Isolate* isolate = masm->isolate();
311
312   DCHECK(!FLAG_vector_ics ||
313          !AreAliased(a4, a5, VectorLoadICDescriptor::SlotRegister(),
314                      VectorLoadICDescriptor::VectorRegister()));
315   __ IncrementCounter(isolate->counters()->load_miss(), 1, a4, a5);
316
317   LoadIC_PushArgs(masm);
318
319   // Perform tail call to the entry.
320   ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
321   int arg_count = FLAG_vector_ics ? 4 : 2;
322   __ TailCallExternalReference(ref, arg_count, 1);
323 }
324
325
326 void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
327   // The return address is in ra.
328
329   __ mov(LoadIC_TempRegister(), LoadDescriptor::ReceiverRegister());
330   __ Push(LoadIC_TempRegister(), LoadDescriptor::NameRegister());
331
332   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
333 }
334
335
336 static MemOperand GenerateMappedArgumentsLookup(
337     MacroAssembler* masm, Register object, Register key, Register scratch1,
338     Register scratch2, Register scratch3, Label* unmapped_case,
339     Label* slow_case) {
340   Heap* heap = masm->isolate()->heap();
341
342   // Check that the receiver is a JSObject. Because of the map check
343   // later, we do not need to check for interceptors or whether it
344   // requires access checks.
345   __ JumpIfSmi(object, slow_case);
346   // Check that the object is some kind of JSObject.
347   __ GetObjectType(object, scratch1, scratch2);
348   __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE));
349
350   // Check that the key is a positive smi.
351   __ NonNegativeSmiTst(key, scratch1);
352   __ Branch(slow_case, ne, scratch1, Operand(zero_reg));
353
354   // Load the elements into scratch1 and check its map.
355   Handle<Map> arguments_map(heap->sloppy_arguments_elements_map());
356   __ ld(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
357   __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
358   // Check if element is in the range of mapped arguments. If not, jump
359   // to the unmapped lookup with the parameter map in scratch1.
360   __ ld(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
361   __ Dsubu(scratch2, scratch2, Operand(Smi::FromInt(2)));
362   __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2));
363
364   // Load element index and check whether it is the hole.
365   const int kOffset =
366       FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
367
368   __ SmiUntag(scratch3, key);
369   __ dsll(scratch3, scratch3, kPointerSizeLog2);
370   __ Daddu(scratch3, scratch3, Operand(kOffset));
371
372   __ Daddu(scratch2, scratch1, scratch3);
373   __ ld(scratch2, MemOperand(scratch2));
374   __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
375   __ Branch(unmapped_case, eq, scratch2, Operand(scratch3));
376
377   // Load value from context and return it. We can reuse scratch1 because
378   // we do not jump to the unmapped lookup (which requires the parameter
379   // map in scratch1).
380   __ ld(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
381   __ SmiUntag(scratch3, scratch2);
382   __ dsll(scratch3, scratch3, kPointerSizeLog2);
383   __ Daddu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
384   __ Daddu(scratch2, scratch1, scratch3);
385   return MemOperand(scratch2);
386 }
387
388
389 static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
390                                                   Register key,
391                                                   Register parameter_map,
392                                                   Register scratch,
393                                                   Label* slow_case) {
394   // Element is in arguments backing store, which is referenced by the
395   // second element of the parameter_map. The parameter_map register
396   // must be loaded with the parameter map of the arguments object and is
397   // overwritten.
398   const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
399   Register backing_store = parameter_map;
400   __ ld(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
401   __ CheckMap(backing_store, scratch, Heap::kFixedArrayMapRootIndex, slow_case,
402               DONT_DO_SMI_CHECK);
403   __ ld(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
404   __ Branch(slow_case, Ugreater_equal, key, Operand(scratch));
405   __ SmiUntag(scratch, key);
406   __ dsll(scratch, scratch, kPointerSizeLog2);
407   __ Daddu(scratch, scratch, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
408   __ Daddu(scratch, backing_store, scratch);
409   return MemOperand(scratch);
410 }
411
412
413 void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
414   Register receiver = StoreDescriptor::ReceiverRegister();
415   Register key = StoreDescriptor::NameRegister();
416   Register value = StoreDescriptor::ValueRegister();
417   DCHECK(value.is(a0));
418
419   Label slow, notin;
420   // Store address is returned in register (of MemOperand) mapped_location.
421   MemOperand mapped_location = GenerateMappedArgumentsLookup(
422       masm, receiver, key, a3, a4, a5, &notin, &slow);
423   __ sd(value, mapped_location);
424   __ mov(t1, value);
425   DCHECK_EQ(mapped_location.offset(), 0);
426   __ RecordWrite(a3, mapped_location.rm(), t1, kRAHasNotBeenSaved,
427                  kDontSaveFPRegs);
428   __ Ret(USE_DELAY_SLOT);
429   __ mov(v0, value);  // (In delay slot) return the value stored in v0.
430   __ bind(&notin);
431   // The unmapped lookup expects that the parameter map is in a3.
432   // Store address is returned in register (of MemOperand) unmapped_location.
433   MemOperand unmapped_location =
434       GenerateUnmappedArgumentsLookup(masm, key, a3, a4, &slow);
435   __ sd(value, unmapped_location);
436   __ mov(t1, value);
437   DCHECK_EQ(unmapped_location.offset(), 0);
438   __ RecordWrite(a3, unmapped_location.rm(), t1, kRAHasNotBeenSaved,
439                  kDontSaveFPRegs);
440   __ Ret(USE_DELAY_SLOT);
441   __ mov(v0, a0);  // (In delay slot) return the value stored in v0.
442   __ bind(&slow);
443   GenerateMiss(masm);
444 }
445
446
447 void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
448   // The return address is in ra.
449   Isolate* isolate = masm->isolate();
450
451   DCHECK(!FLAG_vector_ics ||
452          !AreAliased(a4, a5, VectorLoadICDescriptor::SlotRegister(),
453                      VectorLoadICDescriptor::VectorRegister()));
454   __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a4, a5);
455
456   LoadIC_PushArgs(masm);
457
458   // Perform tail call to the entry.
459   ExternalReference ref =
460       ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
461
462   int arg_count = FLAG_vector_ics ? 4 : 2;
463   __ TailCallExternalReference(ref, arg_count, 1);
464 }
465
466
467 void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
468   // The return address is in ra.
469
470   __ Push(LoadDescriptor::ReceiverRegister(), LoadDescriptor::NameRegister());
471
472   __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
473 }
474
475
476 void KeyedLoadIC::GenerateMegamorphic(MacroAssembler* masm) {
477   // The return address is in ra.
478   Label slow, check_name, index_smi, index_name, property_array_property;
479   Label probe_dictionary, check_number_dictionary;
480
481   Register key = LoadDescriptor::NameRegister();
482   Register receiver = LoadDescriptor::ReceiverRegister();
483   DCHECK(key.is(a2));
484   DCHECK(receiver.is(a1));
485
486   Isolate* isolate = masm->isolate();
487
488   // Check that the key is a smi.
489   __ JumpIfNotSmi(key, &check_name);
490   __ bind(&index_smi);
491   // Now the key is known to be a smi. This place is also jumped to from below
492   // where a numeric string is converted to a smi.
493
494   GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3,
495                                  Map::kHasIndexedInterceptor, &slow);
496
497   // Check the receiver's map to see if it has fast elements.
498   __ CheckFastElements(a0, a3, &check_number_dictionary);
499
500   GenerateFastArrayLoad(masm, receiver, key, a0, a3, a4, v0, &slow);
501   __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a4, a3);
502   __ Ret();
503
504   __ bind(&check_number_dictionary);
505   __ ld(a4, FieldMemOperand(receiver, JSObject::kElementsOffset));
506   __ ld(a3, FieldMemOperand(a4, JSObject::kMapOffset));
507
508   // Check whether the elements is a number dictionary.
509   // a3: elements map
510   // a4: elements
511   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
512   __ Branch(&slow, ne, a3, Operand(at));
513   __ dsra32(a0, key, 0);
514   __ LoadFromNumberDictionary(&slow, a4, key, v0, a0, a3, a5);
515   __ Ret();
516
517   // Slow case, key and receiver still in a2 and a1.
518   __ bind(&slow);
519   __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(), 1, a4,
520                       a3);
521   GenerateRuntimeGetProperty(masm);
522
523   __ bind(&check_name);
524   GenerateKeyNameCheck(masm, key, a0, a3, &index_name, &slow);
525
526   GenerateKeyedLoadReceiverCheck(masm, receiver, a0, a3,
527                                  Map::kHasNamedInterceptor, &slow);
528
529
530   // If the receiver is a fast-case object, check the stub cache. Otherwise
531   // probe the dictionary.
532   __ ld(a3, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
533   __ ld(a4, FieldMemOperand(a3, HeapObject::kMapOffset));
534   __ LoadRoot(at, Heap::kHashTableMapRootIndex);
535   __ Branch(&probe_dictionary, eq, a4, Operand(at));
536
537   if (FLAG_vector_ics) {
538     // When vector ics are in use, the handlers in the stub cache expect a
539     // vector and slot. Since we won't change the IC from any downstream
540     // misses, a dummy vector can be used.
541     Register vector = VectorLoadICDescriptor::VectorRegister();
542     Register slot = VectorLoadICDescriptor::SlotRegister();
543     DCHECK(!AreAliased(vector, slot, a4, a5, a6, t1));
544     Handle<TypeFeedbackVector> dummy_vector = Handle<TypeFeedbackVector>::cast(
545         masm->isolate()->factory()->keyed_load_dummy_vector());
546     int int_slot = dummy_vector->GetIndex(FeedbackVectorICSlot(0));
547     __ LoadRoot(vector, Heap::kKeyedLoadDummyVectorRootIndex);
548     __ li(slot, Operand(Smi::FromInt(int_slot)));
549   }
550
551   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
552       Code::ComputeHandlerFlags(Code::LOAD_IC));
553   masm->isolate()->stub_cache()->GenerateProbe(
554       masm, Code::LOAD_IC, flags, false, receiver, key, a4, a5, a6, t1);
555   // Cache miss.
556   GenerateMiss(masm);
557
558   // Do a quick inline probe of the receiver's dictionary, if it
559   // exists.
560   __ bind(&probe_dictionary);
561   // a3: elements
562   __ ld(a0, FieldMemOperand(receiver, HeapObject::kMapOffset));
563   __ lbu(a0, FieldMemOperand(a0, Map::kInstanceTypeOffset));
564   GenerateGlobalInstanceTypeCheck(masm, a0, &slow);
565   // Load the property to v0.
566   GenerateDictionaryLoad(masm, &slow, a3, key, v0, a5, a4);
567   __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(), 1, a4,
568                       a3);
569   __ Ret();
570
571   __ bind(&index_name);
572   __ IndexFromHash(a3, key);
573   // Now jump to the place where smi keys are handled.
574   __ Branch(&index_smi);
575 }
576
577
578 static void KeyedStoreGenerateMegamorphicHelper(
579     MacroAssembler* masm, Label* fast_object, Label* fast_double, Label* slow,
580     KeyedStoreCheckMap check_map, KeyedStoreIncrementLength increment_length,
581     Register value, Register key, Register receiver, Register receiver_map,
582     Register elements_map, Register elements) {
583   Label transition_smi_elements;
584   Label finish_object_store, non_double_value, transition_double_elements;
585   Label fast_double_without_map_check;
586
587   // Fast case: Do the store, could be either Object or double.
588   __ bind(fast_object);
589   Register scratch_value = a4;
590   Register address = a5;
591   if (check_map == kCheckMap) {
592     __ ld(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
593     __ Branch(fast_double, ne, elements_map,
594               Operand(masm->isolate()->factory()->fixed_array_map()));
595   }
596
597   // HOLECHECK: guards "A[i] = V"
598   // We have to go to the runtime if the current value is the hole because
599   // there may be a callback on the element.
600   Label holecheck_passed1;
601   __ Daddu(address, elements, FixedArray::kHeaderSize - kHeapObjectTag);
602   __ SmiScale(at, key, kPointerSizeLog2);
603   __ daddu(address, address, at);
604   __ ld(scratch_value, MemOperand(address));
605
606   __ Branch(&holecheck_passed1, ne, scratch_value,
607             Operand(masm->isolate()->factory()->the_hole_value()));
608   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
609                                       slow);
610
611   __ bind(&holecheck_passed1);
612
613   // Smi stores don't require further checks.
614   Label non_smi_value;
615   __ JumpIfNotSmi(value, &non_smi_value);
616
617   if (increment_length == kIncrementLength) {
618     // Add 1 to receiver->length.
619     __ Daddu(scratch_value, key, Operand(Smi::FromInt(1)));
620     __ sd(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
621   }
622   // It's irrelevant whether array is smi-only or not when writing a smi.
623   __ Daddu(address, elements,
624            Operand(FixedArray::kHeaderSize - kHeapObjectTag));
625   __ SmiScale(scratch_value, key, kPointerSizeLog2);
626   __ Daddu(address, address, scratch_value);
627   __ sd(value, MemOperand(address));
628   __ Ret();
629
630   __ bind(&non_smi_value);
631   // Escape to elements kind transition case.
632   __ CheckFastObjectElements(receiver_map, scratch_value,
633                              &transition_smi_elements);
634
635   // Fast elements array, store the value to the elements backing store.
636   __ bind(&finish_object_store);
637   if (increment_length == kIncrementLength) {
638     // Add 1 to receiver->length.
639     __ Daddu(scratch_value, key, Operand(Smi::FromInt(1)));
640     __ sd(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
641   }
642   __ Daddu(address, elements,
643            Operand(FixedArray::kHeaderSize - kHeapObjectTag));
644   __ SmiScale(scratch_value, key, kPointerSizeLog2);
645   __ Daddu(address, address, scratch_value);
646   __ sd(value, MemOperand(address));
647   // Update write barrier for the elements array address.
648   __ mov(scratch_value, value);  // Preserve the value which is returned.
649   __ RecordWrite(elements, address, scratch_value, kRAHasNotBeenSaved,
650                  kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
651   __ Ret();
652
653   __ bind(fast_double);
654   if (check_map == kCheckMap) {
655     // Check for fast double array case. If this fails, call through to the
656     // runtime.
657     __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
658     __ Branch(slow, ne, elements_map, Operand(at));
659   }
660
661   // HOLECHECK: guards "A[i] double hole?"
662   // We have to see if the double version of the hole is present. If so
663   // go to the runtime.
664   __ Daddu(address, elements,
665            Operand(FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32) -
666                    kHeapObjectTag));
667   __ SmiScale(at, key, kPointerSizeLog2);
668   __ daddu(address, address, at);
669   __ lw(scratch_value, MemOperand(address));
670   __ Branch(&fast_double_without_map_check, ne, scratch_value,
671             Operand(static_cast<int32_t>(kHoleNanUpper32)));
672   __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
673                                       slow);
674
675   __ bind(&fast_double_without_map_check);
676   __ StoreNumberToDoubleElements(value, key,
677                                  elements,  // Overwritten.
678                                  a3,        // Scratch regs...
679                                  a4, &transition_double_elements);
680   if (increment_length == kIncrementLength) {
681     // Add 1 to receiver->length.
682     __ Daddu(scratch_value, key, Operand(Smi::FromInt(1)));
683     __ sd(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
684   }
685   __ Ret();
686
687   __ bind(&transition_smi_elements);
688   // Transition the array appropriately depending on the value type.
689   __ ld(a4, FieldMemOperand(value, HeapObject::kMapOffset));
690   __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
691   __ Branch(&non_double_value, ne, a4, Operand(at));
692
693   // Value is a double. Transition FAST_SMI_ELEMENTS ->
694   // FAST_DOUBLE_ELEMENTS and complete the store.
695   __ LoadTransitionedArrayMapConditional(
696       FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS, receiver_map, a4, slow);
697   AllocationSiteMode mode =
698       AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_DOUBLE_ELEMENTS);
699   ElementsTransitionGenerator::GenerateSmiToDouble(masm, receiver, key, value,
700                                                    receiver_map, mode, slow);
701   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
702   __ jmp(&fast_double_without_map_check);
703
704   __ bind(&non_double_value);
705   // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
706   __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS, FAST_ELEMENTS,
707                                          receiver_map, a4, slow);
708   mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
709   ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
710       masm, receiver, key, value, receiver_map, mode, slow);
711   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
712   __ jmp(&finish_object_store);
713
714   __ bind(&transition_double_elements);
715   // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
716   // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
717   // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
718   __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS,
719                                          receiver_map, a4, slow);
720   mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
721   ElementsTransitionGenerator::GenerateDoubleToObject(
722       masm, receiver, key, value, receiver_map, mode, slow);
723   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
724   __ jmp(&finish_object_store);
725 }
726
727
728 void KeyedStoreIC::GenerateMegamorphic(MacroAssembler* masm,
729                                        LanguageMode language_mode) {
730   // ---------- S t a t e --------------
731   //  -- a0     : value
732   //  -- a1     : key
733   //  -- a2     : receiver
734   //  -- ra     : return address
735   // -----------------------------------
736   Label slow, fast_object, fast_object_grow;
737   Label fast_double, fast_double_grow;
738   Label array, extra, check_if_double_array, maybe_name_key, miss;
739
740   // Register usage.
741   Register value = StoreDescriptor::ValueRegister();
742   Register key = StoreDescriptor::NameRegister();
743   Register receiver = StoreDescriptor::ReceiverRegister();
744   DCHECK(value.is(a0));
745   Register receiver_map = a3;
746   Register elements_map = a6;
747   Register elements = a7;  // Elements array of the receiver.
748   // a4 and a5 are used as general scratch registers.
749
750   // Check that the key is a smi.
751   __ JumpIfNotSmi(key, &maybe_name_key);
752   // Check that the object isn't a smi.
753   __ JumpIfSmi(receiver, &slow);
754   // Get the map of the object.
755   __ ld(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
756   // Check that the receiver does not require access checks and is not observed.
757   // The generic stub does not perform map checks or handle observed objects.
758   __ lbu(a4, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
759   __ And(a4, a4,
760          Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
761   __ Branch(&slow, ne, a4, Operand(zero_reg));
762   // Check if the object is a JS array or not.
763   __ lbu(a4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
764   __ Branch(&array, eq, a4, Operand(JS_ARRAY_TYPE));
765   // Check that the object is some kind of JSObject.
766   __ Branch(&slow, lt, a4, Operand(FIRST_JS_OBJECT_TYPE));
767
768   // Object case: Check key against length in the elements array.
769   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
770   // Check array bounds. Both the key and the length of FixedArray are smis.
771   __ ld(a4, FieldMemOperand(elements, FixedArray::kLengthOffset));
772   __ Branch(&fast_object, lo, key, Operand(a4));
773
774   // Slow case, handle jump to runtime.
775   __ bind(&slow);
776   // Entry registers are intact.
777   // a0: value.
778   // a1: key.
779   // a2: receiver.
780   PropertyICCompiler::GenerateRuntimeSetProperty(masm, language_mode);
781   // Never returns to here.
782
783   __ bind(&maybe_name_key);
784   __ ld(a4, FieldMemOperand(key, HeapObject::kMapOffset));
785   __ lb(a4, FieldMemOperand(a4, Map::kInstanceTypeOffset));
786   __ JumpIfNotUniqueNameInstanceType(a4, &slow);
787   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
788       Code::ComputeHandlerFlags(Code::STORE_IC));
789   masm->isolate()->stub_cache()->GenerateProbe(
790       masm, Code::STORE_IC, flags, false, receiver, key, a3, a4, a5, a6);
791   // Cache miss.
792   __ Branch(&miss);
793
794   // Extra capacity case: Check if there is extra capacity to
795   // perform the store and update the length. Used for adding one
796   // element to the array by writing to array[array.length].
797   __ bind(&extra);
798   // Condition code from comparing key and array length is still available.
799   // Only support writing to array[array.length].
800   __ Branch(&slow, ne, key, Operand(a4));
801   // Check for room in the elements backing store.
802   // Both the key and the length of FixedArray are smis.
803   __ ld(a4, FieldMemOperand(elements, FixedArray::kLengthOffset));
804   __ Branch(&slow, hs, key, Operand(a4));
805   __ ld(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
806   __ Branch(&check_if_double_array, ne, elements_map,
807             Heap::kFixedArrayMapRootIndex);
808
809   __ jmp(&fast_object_grow);
810
811   __ bind(&check_if_double_array);
812   __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
813   __ jmp(&fast_double_grow);
814
815   // Array case: Get the length and the elements array from the JS
816   // array. Check that the array is in fast mode (and writable); if it
817   // is the length is always a smi.
818   __ bind(&array);
819   __ ld(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
820
821   // Check the key against the length in the array.
822   __ ld(a4, FieldMemOperand(receiver, JSArray::kLengthOffset));
823   __ Branch(&extra, hs, key, Operand(a4));
824
825   KeyedStoreGenerateMegamorphicHelper(
826       masm, &fast_object, &fast_double, &slow, kCheckMap, kDontIncrementLength,
827       value, key, receiver, receiver_map, elements_map, elements);
828   KeyedStoreGenerateMegamorphicHelper(masm, &fast_object_grow,
829                                       &fast_double_grow, &slow, kDontCheckMap,
830                                       kIncrementLength, value, key, receiver,
831                                       receiver_map, elements_map, elements);
832
833   __ bind(&miss);
834   GenerateMiss(masm);
835 }
836
837
838 void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
839   // Push receiver, key and value for runtime call.
840   __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
841           StoreDescriptor::ValueRegister());
842
843   ExternalReference ref =
844       ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
845   __ TailCallExternalReference(ref, 3, 1);
846 }
847
848
849 void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
850   Register receiver = StoreDescriptor::ReceiverRegister();
851   Register name = StoreDescriptor::NameRegister();
852   DCHECK(receiver.is(a1));
853   DCHECK(name.is(a2));
854   DCHECK(StoreDescriptor::ValueRegister().is(a0));
855
856   // Get the receiver from the stack and probe the stub cache.
857   Code::Flags flags = Code::RemoveTypeAndHolderFromFlags(
858       Code::ComputeHandlerFlags(Code::STORE_IC));
859   masm->isolate()->stub_cache()->GenerateProbe(
860       masm, Code::STORE_IC, flags, false, receiver, name, a3, a4, a5, a6);
861
862   // Cache miss: Jump to runtime.
863   GenerateMiss(masm);
864 }
865
866
867 void StoreIC::GenerateMiss(MacroAssembler* masm) {
868   __ Push(StoreDescriptor::ReceiverRegister(), StoreDescriptor::NameRegister(),
869           StoreDescriptor::ValueRegister());
870   // Perform tail call to the entry.
871   ExternalReference ref =
872       ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
873   __ TailCallExternalReference(ref, 3, 1);
874 }
875
876
877 void StoreIC::GenerateNormal(MacroAssembler* masm) {
878   Label miss;
879   Register receiver = StoreDescriptor::ReceiverRegister();
880   Register name = StoreDescriptor::NameRegister();
881   Register value = StoreDescriptor::ValueRegister();
882   Register dictionary = a3;
883   DCHECK(!AreAliased(value, receiver, name, dictionary, a4, a5));
884
885   __ ld(dictionary, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
886
887   GenerateDictionaryStore(masm, &miss, a3, name, value, a4, a5);
888   Counters* counters = masm->isolate()->counters();
889   __ IncrementCounter(counters->store_normal_hit(), 1, a4, a5);
890   __ Ret();
891
892   __ bind(&miss);
893   __ IncrementCounter(counters->store_normal_miss(), 1, a4, a5);
894   GenerateMiss(masm);
895 }
896
897
898 #undef __
899
900
901 Condition CompareIC::ComputeCondition(Token::Value op) {
902   switch (op) {
903     case Token::EQ_STRICT:
904     case Token::EQ:
905       return eq;
906     case Token::LT:
907       return lt;
908     case Token::GT:
909       return gt;
910     case Token::LTE:
911       return le;
912     case Token::GTE:
913       return ge;
914     default:
915       UNREACHABLE();
916       return kNoCondition;
917   }
918 }
919
920
921 bool CompareIC::HasInlinedSmiCode(Address address) {
922   // The address of the instruction following the call.
923   Address andi_instruction_address =
924       address + Assembler::kCallTargetAddressOffset;
925
926   // If the instruction following the call is not a andi at, rx, #yyy, nothing
927   // was inlined.
928   Instr instr = Assembler::instr_at(andi_instruction_address);
929   return Assembler::IsAndImmediate(instr) &&
930          Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
931 }
932
933
934 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
935   Address andi_instruction_address =
936       address + Assembler::kCallTargetAddressOffset;
937
938   // If the instruction following the call is not a andi at, rx, #yyy, nothing
939   // was inlined.
940   Instr instr = Assembler::instr_at(andi_instruction_address);
941   if (!(Assembler::IsAndImmediate(instr) &&
942         Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
943     return;
944   }
945
946   // The delta to the start of the map check instruction and the
947   // condition code uses at the patched jump.
948   int delta = Assembler::GetImmediate16(instr);
949   delta += Assembler::GetRs(instr) * kImm16Mask;
950   // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
951   // signals that nothing was inlined.
952   if (delta == 0) {
953     return;
954   }
955
956   if (FLAG_trace_ic) {
957     PrintF("[  patching ic at %p, andi=%p, delta=%d\n", address,
958            andi_instruction_address, delta);
959   }
960
961   Address patch_address =
962       andi_instruction_address - delta * Instruction::kInstrSize;
963   Instr instr_at_patch = Assembler::instr_at(patch_address);
964   Instr branch_instr =
965       Assembler::instr_at(patch_address + Instruction::kInstrSize);
966   // This is patching a conditional "jump if not smi/jump if smi" site.
967   // Enabling by changing from
968   //   andi at, rx, 0
969   //   Branch <target>, eq, at, Operand(zero_reg)
970   // to:
971   //   andi at, rx, #kSmiTagMask
972   //   Branch <target>, ne, at, Operand(zero_reg)
973   // and vice-versa to be disabled again.
974   CodePatcher patcher(patch_address, 2);
975   Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
976   if (check == ENABLE_INLINED_SMI_CHECK) {
977     DCHECK(Assembler::IsAndImmediate(instr_at_patch));
978     DCHECK_EQ(0u, Assembler::GetImmediate16(instr_at_patch));
979     patcher.masm()->andi(at, reg, kSmiTagMask);
980   } else {
981     DCHECK_EQ(check, DISABLE_INLINED_SMI_CHECK);
982     DCHECK(Assembler::IsAndImmediate(instr_at_patch));
983     patcher.masm()->andi(at, reg, 0);
984   }
985   DCHECK(Assembler::IsBranch(branch_instr));
986   if (Assembler::IsBeq(branch_instr)) {
987     patcher.ChangeBranchCondition(ne);
988   } else {
989     DCHECK(Assembler::IsBne(branch_instr));
990     patcher.ChangeBranchCondition(eq);
991   }
992 }
993 }
994 }  // namespace v8::internal
995
996 #endif  // V8_TARGET_ARCH_MIPS64