1// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#if defined(V8_TARGET_ARCH_X64)
31
32#include "codegen.h"
33#include "ic-inl.h"
34#include "runtime.h"
35#include "stub-cache.h"
36
37namespace v8 {
38namespace internal {
39
40// ----------------------------------------------------------------------------
41// Static IC stub generators.
42//
43
44#define __ ACCESS_MASM(masm)
45
46
47static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
48                                            Register type,
49                                            Label* global_object) {
50  // Register usage:
51  //   type: holds the receiver instance type on entry.
52  __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE));
53  __ j(equal, global_object);
54  __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE));
55  __ j(equal, global_object);
56  __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE));
57  __ j(equal, global_object);
58}
59
60
61// Generated code falls through if the receiver is a regular non-global
62// JS object with slow properties and no interceptors.
63static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
64                                                  Register receiver,
65                                                  Register r0,
66                                                  Register r1,
67                                                  Label* miss) {
68  // Register usage:
69  //   receiver: holds the receiver on entry and is unchanged.
70  //   r0: used to hold receiver instance type.
71  //       Holds the property dictionary on fall through.
72  //   r1: used to hold receivers map.
73
74  __ JumpIfSmi(receiver, miss);
75
76  // Check that the receiver is a valid JS object.
77  __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset));
78  __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
79  __ cmpb(r0, Immediate(FIRST_SPEC_OBJECT_TYPE));
80  __ j(below, miss);
81
82  // If this assert fails, we have to check upper bound too.
83  STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
84
85  GenerateGlobalInstanceTypeCheck(masm, r0, miss);
86
87  // Check for non-global object that requires access check.
88  __ testb(FieldOperand(r1, Map::kBitFieldOffset),
89           Immediate((1 << Map::kIsAccessCheckNeeded) |
90                     (1 << Map::kHasNamedInterceptor)));
91  __ j(not_zero, miss);
92
93  __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
94  __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset),
95                 Heap::kHashTableMapRootIndex);
96  __ j(not_equal, miss);
97}
98
99
100
101// Helper function used to load a property from a dictionary backing storage.
102// This function may return false negatives, so miss_label
103// must always call a backup property load that is complete.
104// This function is safe to call if name is not a symbol, and will jump to
105// the miss_label in that case.
106// The generated code assumes that the receiver has slow properties,
107// is not a global object and does not have interceptors.
108static void GenerateDictionaryLoad(MacroAssembler* masm,
109                                   Label* miss_label,
110                                   Register elements,
111                                   Register name,
112                                   Register r0,
113                                   Register r1,
114                                   Register result) {
115  // Register use:
116  //
117  // elements - holds the property dictionary on entry and is unchanged.
118  //
119  // name - holds the name of the property on entry and is unchanged.
120  //
121  // r0   - used to hold the capacity of the property dictionary.
122  //
123  // r1   - used to hold the index into the property dictionary.
124  //
125  // result - holds the result on exit if the load succeeded.
126
127  Label done;
128
129  // Probe the dictionary.
130  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
131                                                     miss_label,
132                                                     &done,
133                                                     elements,
134                                                     name,
135                                                     r0,
136                                                     r1);
137
138  // If probing finds an entry in the dictionary, r0 contains the
139  // index into the dictionary. Check that the value is a normal
140  // property.
141  __ bind(&done);
142  const int kElementsStartOffset =
143      StringDictionary::kHeaderSize +
144      StringDictionary::kElementsStartIndex * kPointerSize;
145  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
146  __ Test(Operand(elements, r1, times_pointer_size,
147                  kDetailsOffset - kHeapObjectTag),
148          Smi::FromInt(PropertyDetails::TypeField::kMask));
149  __ j(not_zero, miss_label);
150
151  // Get the value at the masked, scaled index.
152  const int kValueOffset = kElementsStartOffset + kPointerSize;
153  __ movq(result,
154          Operand(elements, r1, times_pointer_size,
155                  kValueOffset - kHeapObjectTag));
156}
157
158
159// Helper function used to store a property to a dictionary backing
160// storage. This function may fail to store a property even though it
161// is in the dictionary, so code at miss_label must always call a
162// backup property store that is complete. This function is safe to
163// call if name is not a symbol, and will jump to the miss_label in
164// that case. The generated code assumes that the receiver has slow
165// properties, is not a global object and does not have interceptors.
166static void GenerateDictionaryStore(MacroAssembler* masm,
167                                    Label* miss_label,
168                                    Register elements,
169                                    Register name,
170                                    Register value,
171                                    Register scratch0,
172                                    Register scratch1) {
173  // Register use:
174  //
175  // elements - holds the property dictionary on entry and is clobbered.
176  //
177  // name - holds the name of the property on entry and is unchanged.
178  //
179  // value - holds the value to store and is unchanged.
180  //
181  // scratch0 - used for index into the property dictionary and is clobbered.
182  //
183  // scratch1 - used to hold the capacity of the property dictionary and is
184  //            clobbered.
185  Label done;
186
187  // Probe the dictionary.
188  StringDictionaryLookupStub::GeneratePositiveLookup(masm,
189                                                     miss_label,
190                                                     &done,
191                                                     elements,
192                                                     name,
193                                                     scratch0,
194                                                     scratch1);
195
196  // If probing finds an entry in the dictionary, scratch0 contains the
197  // index into the dictionary. Check that the value is a normal
198  // property that is not read only.
199  __ bind(&done);
200  const int kElementsStartOffset =
201      StringDictionary::kHeaderSize +
202      StringDictionary::kElementsStartIndex * kPointerSize;
203  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
204  const int kTypeAndReadOnlyMask =
205      (PropertyDetails::TypeField::kMask |
206       PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
207  __ Test(Operand(elements,
208                  scratch1,
209                  times_pointer_size,
210                  kDetailsOffset - kHeapObjectTag),
211          Smi::FromInt(kTypeAndReadOnlyMask));
212  __ j(not_zero, miss_label);
213
214  // Store the value at the masked, scaled index.
215  const int kValueOffset = kElementsStartOffset + kPointerSize;
216  __ lea(scratch1, Operand(elements,
217                           scratch1,
218                           times_pointer_size,
219                           kValueOffset - kHeapObjectTag));
220  __ movq(Operand(scratch1, 0), value);
221
222  // Update write barrier. Make sure not to clobber the value.
223  __ movq(scratch0, value);
224  __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs);
225}
226
227
228void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
229  // ----------- S t a t e -------------
230  //  -- rax    : receiver
231  //  -- rcx    : name
232  //  -- rsp[0] : return address
233  // -----------------------------------
234  Label miss;
235
236  StubCompiler::GenerateLoadArrayLength(masm, rax, rdx, &miss);
237  __ bind(&miss);
238  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
239}
240
241
242void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
243  // ----------- S t a t e -------------
244  //  -- rax    : receiver
245  //  -- rcx    : name
246  //  -- rsp[0] : return address
247  // -----------------------------------
248  Label miss;
249
250  StubCompiler::GenerateLoadStringLength(masm, rax, rdx, rbx, &miss,
251                                         support_wrappers);
252  __ bind(&miss);
253  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
254}
255
256
257void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
258  // ----------- S t a t e -------------
259  //  -- rax    : receiver
260  //  -- rcx    : name
261  //  -- rsp[0] : return address
262  // -----------------------------------
263  Label miss;
264
265  StubCompiler::GenerateLoadFunctionPrototype(masm, rax, rdx, rbx, &miss);
266  __ bind(&miss);
267  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
268}
269
270
271// Checks the receiver for special cases (value type, slow case bits).
272// Falls through for regular JS object.
273static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
274                                           Register receiver,
275                                           Register map,
276                                           int interceptor_bit,
277                                           Label* slow) {
278  // Register use:
279  //   receiver - holds the receiver and is unchanged.
280  // Scratch registers:
281  //   map - used to hold the map of the receiver.
282
283  // Check that the object isn't a smi.
284  __ JumpIfSmi(receiver, slow);
285
286  // Check that the object is some kind of JS object EXCEPT JS Value type.
287  // In the case that the object is a value-wrapper object,
288  // we enter the runtime system to make sure that indexing
289  // into string objects work as intended.
290  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
291  __ CmpObjectType(receiver, JS_OBJECT_TYPE, map);
292  __ j(below, slow);
293
294  // Check bit field.
295  __ testb(FieldOperand(map, Map::kBitFieldOffset),
296           Immediate((1 << Map::kIsAccessCheckNeeded) |
297                     (1 << interceptor_bit)));
298  __ j(not_zero, slow);
299}
300
301
302// Loads an indexed element from a fast case array.
303// If not_fast_array is NULL, doesn't perform the elements map check.
304static void GenerateFastArrayLoad(MacroAssembler* masm,
305                                  Register receiver,
306                                  Register key,
307                                  Register elements,
308                                  Register scratch,
309                                  Register result,
310                                  Label* not_fast_array,
311                                  Label* out_of_range) {
312  // Register use:
313  //
314  // receiver - holds the receiver on entry.
315  //            Unchanged unless 'result' is the same register.
316  //
317  // key      - holds the smi key on entry.
318  //            Unchanged unless 'result' is the same register.
319  //
320  // elements - holds the elements of the receiver on exit.
321  //
322  // result   - holds the result on exit if the load succeeded.
323  //            Allowed to be the the same as 'receiver' or 'key'.
324  //            Unchanged on bailout so 'receiver' and 'key' can be safely
325  //            used by further computation.
326  //
327  // Scratch registers:
328  //
329  //   scratch - used to hold elements of the receiver and the loaded value.
330
331  __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
332  if (not_fast_array != NULL) {
333    // Check that the object is in fast mode and writable.
334    __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
335                   Heap::kFixedArrayMapRootIndex);
336    __ j(not_equal, not_fast_array);
337  } else {
338    __ AssertFastElements(elements);
339  }
340  // Check that the key (index) is within bounds.
341  __ SmiCompare(key, FieldOperand(elements, FixedArray::kLengthOffset));
342  // Unsigned comparison rejects negative indices.
343  __ j(above_equal, out_of_range);
344  // Fast case: Do the load.
345  SmiIndex index = masm->SmiToIndex(scratch, key, kPointerSizeLog2);
346  __ movq(scratch, FieldOperand(elements,
347                                index.reg,
348                                index.scale,
349                                FixedArray::kHeaderSize));
350  __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex);
351  // In case the loaded value is the_hole we have to consult GetProperty
352  // to ensure the prototype chain is searched.
353  __ j(equal, out_of_range);
354  if (!result.is(scratch)) {
355    __ movq(result, scratch);
356  }
357}
358
359
360// Checks whether a key is an array index string or a symbol string.
361// Falls through if the key is a symbol.
362static void GenerateKeyStringCheck(MacroAssembler* masm,
363                                   Register key,
364                                   Register map,
365                                   Register hash,
366                                   Label* index_string,
367                                   Label* not_symbol) {
368  // Register use:
369  //   key - holds the key and is unchanged. Assumed to be non-smi.
370  // Scratch registers:
371  //   map - used to hold the map of the key.
372  //   hash - used to hold the hash of the key.
373  __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
374  __ j(above_equal, not_symbol);
375  // Is the string an array index, with cached numeric value?
376  __ movl(hash, FieldOperand(key, String::kHashFieldOffset));
377  __ testl(hash, Immediate(String::kContainsCachedArrayIndexMask));
378  __ j(zero, index_string);  // The value in hash is used at jump target.
379
380  // Is the string a symbol?
381  STATIC_ASSERT(kSymbolTag != 0);
382  __ testb(FieldOperand(map, Map::kInstanceTypeOffset),
383           Immediate(kIsSymbolMask));
384  __ j(zero, not_symbol);
385}
386
387
388
389void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
390  // ----------- S t a t e -------------
391  //  -- rax    : key
392  //  -- rdx    : receiver
393  //  -- rsp[0] : return address
394  // -----------------------------------
395  Label slow, check_string, index_smi, index_string, property_array_property;
396  Label probe_dictionary, check_number_dictionary;
397
398  // Check that the key is a smi.
399  __ JumpIfNotSmi(rax, &check_string);
400  __ bind(&index_smi);
401  // Now the key is known to be a smi. This place is also jumped to from below
402  // where a numeric string is converted to a smi.
403
404  GenerateKeyedLoadReceiverCheck(
405      masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
406
407  // Check the receiver's map to see if it has fast elements.
408  __ CheckFastElements(rcx, &check_number_dictionary);
409
410  GenerateFastArrayLoad(masm,
411                        rdx,
412                        rax,
413                        rcx,
414                        rbx,
415                        rax,
416                        NULL,
417                        &slow);
418  Counters* counters = masm->isolate()->counters();
419  __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
420  __ ret(0);
421
422  __ bind(&check_number_dictionary);
423  __ SmiToInteger32(rbx, rax);
424  __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
425
426  // Check whether the elements is a number dictionary.
427  // rdx: receiver
428  // rax: key
429  // rbx: key as untagged int32
430  // rcx: elements
431  __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
432                 Heap::kHashTableMapRootIndex);
433  __ j(not_equal, &slow);
434  __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
435  __ ret(0);
436
437  __ bind(&slow);
438  // Slow case: Jump to runtime.
439  // rdx: receiver
440  // rax: key
441  __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
442  GenerateRuntimeGetProperty(masm);
443
444  __ bind(&check_string);
445  GenerateKeyStringCheck(masm, rax, rcx, rbx, &index_string, &slow);
446
447  GenerateKeyedLoadReceiverCheck(
448      masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
449
450  // If the receiver is a fast-case object, check the keyed lookup
451  // cache. Otherwise probe the dictionary leaving result in rcx.
452  __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
453  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
454                 Heap::kHashTableMapRootIndex);
455  __ j(equal, &probe_dictionary);
456
457  // Load the map of the receiver, compute the keyed lookup cache hash
458  // based on 32 bits of the map pointer and the string hash.
459  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
460  __ movl(rcx, rbx);
461  __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift));
462  __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset));
463  __ shr(rdi, Immediate(String::kHashShift));
464  __ xor_(rcx, rdi);
465  int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
466  __ and_(rcx, Immediate(mask));
467
468  // Load the key (consisting of map and symbol) from the cache and
469  // check for match.
470  Label load_in_object_property;
471  static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
472  Label hit_on_nth_entry[kEntriesPerBucket];
473  ExternalReference cache_keys
474      = ExternalReference::keyed_lookup_cache_keys(masm->isolate());
475
476  for (int i = 0; i < kEntriesPerBucket - 1; i++) {
477    Label try_next_entry;
478    __ movq(rdi, rcx);
479    __ shl(rdi, Immediate(kPointerSizeLog2 + 1));
480    __ LoadAddress(kScratchRegister, cache_keys);
481    int off = kPointerSize * i * 2;
482    __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
483    __ j(not_equal, &try_next_entry);
484    __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
485    __ j(equal, &hit_on_nth_entry[i]);
486    __ bind(&try_next_entry);
487  }
488
489  int off = kPointerSize * (kEntriesPerBucket - 1) * 2;
490  __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
491  __ j(not_equal, &slow);
492  __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
493  __ j(not_equal, &slow);
494
495  // Get field offset, which is a 32-bit integer.
496  ExternalReference cache_field_offsets
497      = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
498
499  // Hit on nth entry.
500  for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
501    __ bind(&hit_on_nth_entry[i]);
502    if (i != 0) {
503      __ addl(rcx, Immediate(i));
504    }
505    __ LoadAddress(kScratchRegister, cache_field_offsets);
506    __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0));
507    __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset));
508    __ subq(rdi, rcx);
509    __ j(above_equal, &property_array_property);
510    if (i != 0) {
511      __ jmp(&load_in_object_property);
512    }
513  }
514
515  // Load in-object property.
516  __ bind(&load_in_object_property);
517  __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
518  __ addq(rcx, rdi);
519  __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0));
520  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
521  __ ret(0);
522
523  // Load property array property.
524  __ bind(&property_array_property);
525  __ movq(rax, FieldOperand(rdx, JSObject::kPropertiesOffset));
526  __ movq(rax, FieldOperand(rax, rdi, times_pointer_size,
527                            FixedArray::kHeaderSize));
528  __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
529  __ ret(0);
530
531  // Do a quick inline probe of the receiver's dictionary, if it
532  // exists.
533  __ bind(&probe_dictionary);
534  // rdx: receiver
535  // rax: key
536  // rbx: elements
537
538  __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
539  __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
540  GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
541
542  GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
543  __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
544  __ ret(0);
545
546  __ bind(&index_string);
547  __ IndexFromHash(rbx, rax);
548  __ jmp(&index_smi);
549}
550
551
552void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
553  // ----------- S t a t e -------------
554  //  -- rax    : key
555  //  -- rdx    : receiver
556  //  -- rsp[0] : return address
557  // -----------------------------------
558  Label miss;
559
560  Register receiver = rdx;
561  Register index = rax;
562  Register scratch = rcx;
563  Register result = rax;
564
565  StringCharAtGenerator char_at_generator(receiver,
566                                          index,
567                                          scratch,
568                                          result,
569                                          &miss,  // When not a string.
570                                          &miss,  // When not a number.
571                                          &miss,  // When index out of range.
572                                          STRING_INDEX_IS_ARRAY_INDEX);
573  char_at_generator.GenerateFast(masm);
574  __ ret(0);
575
576  StubRuntimeCallHelper call_helper;
577  char_at_generator.GenerateSlow(masm, call_helper);
578
579  __ bind(&miss);
580  GenerateMiss(masm, false);
581}
582
583
584void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
585  // ----------- S t a t e -------------
586  //  -- rax    : key
587  //  -- rdx    : receiver
588  //  -- rsp[0] : return address
589  // -----------------------------------
590  Label slow;
591
592  // Check that the receiver isn't a smi.
593  __ JumpIfSmi(rdx, &slow);
594
595  // Check that the key is an array index, that is Uint32.
596  STATIC_ASSERT(kSmiValueSize <= 32);
597  __ JumpUnlessNonNegativeSmi(rax, &slow);
598
599  // Get the map of the receiver.
600  __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
601
602  // Check that it has indexed interceptor and access checks
603  // are not enabled for this object.
604  __ movb(rcx, FieldOperand(rcx, Map::kBitFieldOffset));
605  __ andb(rcx, Immediate(kSlowCaseBitFieldMask));
606  __ cmpb(rcx, Immediate(1 << Map::kHasIndexedInterceptor));
607  __ j(not_zero, &slow);
608
609  // Everything is fine, call runtime.
610  __ pop(rcx);
611  __ push(rdx);  // receiver
612  __ push(rax);  // key
613  __ push(rcx);  // return address
614
615  // Perform tail call to the entry.
616  __ TailCallExternalReference(
617      ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
618                        masm->isolate()),
619      2,
620      1);
621
622  __ bind(&slow);
623  GenerateMiss(masm, false);
624}
625
626
627void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
628                                   StrictModeFlag strict_mode) {
629  // ----------- S t a t e -------------
630  //  -- rax     : value
631  //  -- rcx     : key
632  //  -- rdx     : receiver
633  //  -- rsp[0]  : return address
634  // -----------------------------------
635  Label slow, slow_with_tagged_index, fast, array, extra, check_extra_double;
636  Label fast_object_with_map_check, fast_object_without_map_check;
637  Label fast_double_with_map_check, fast_double_without_map_check;
638  Label transition_smi_elements, finish_object_store, non_double_value;
639  Label transition_double_elements;
640
641  // Check that the object isn't a smi.
642  __ JumpIfSmi(rdx, &slow_with_tagged_index);
643  // Get the map from the receiver.
644  __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
645  // Check that the receiver does not require access checks.  We need
646  // to do this because this generic stub does not perform map checks.
647  __ testb(FieldOperand(r9, Map::kBitFieldOffset),
648           Immediate(1 << Map::kIsAccessCheckNeeded));
649  __ j(not_zero, &slow_with_tagged_index);
650  // Check that the key is a smi.
651  __ JumpIfNotSmi(rcx, &slow_with_tagged_index);
652  __ SmiToInteger32(rcx, rcx);
653
654  __ CmpInstanceType(r9, JS_ARRAY_TYPE);
655  __ j(equal, &array);
656  // Check that the object is some kind of JSObject.
657  __ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE);
658  __ j(below, &slow);
659
660  // Object case: Check key against length in the elements array.
661  // rax: value
662  // rdx: JSObject
663  // rcx: index
664  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
665  // Check array bounds.
666  __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
667  // rax: value
668  // rbx: FixedArray
669  // rcx: index
670  __ j(above, &fast_object_with_map_check);
671
672  // Slow case: call runtime.
673  __ bind(&slow);
674  __ Integer32ToSmi(rcx, rcx);
675  __ bind(&slow_with_tagged_index);
676  GenerateRuntimeSetProperty(masm, strict_mode);
677  // Never returns to here.
678
679  // Extra capacity case: Check if there is extra capacity to
680  // perform the store and update the length. Used for adding one
681  // element to the array by writing to array[array.length].
682  __ bind(&extra);
683  // rax: value
684  // rdx: receiver (a JSArray)
685  // rbx: receiver's elements array (a FixedArray)
686  // rcx: index
687  // flags: smicompare (rdx.length(), rbx)
688  __ j(not_equal, &slow);  // do not leave holes in the array
689  __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
690  __ j(below_equal, &slow);
691  // Increment index to get new length.
692  __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
693  __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
694  __ j(not_equal, &check_extra_double);
695  __ leal(rdi, Operand(rcx, 1));
696  __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
697  __ jmp(&fast_object_without_map_check);
698
699  __ bind(&check_extra_double);
700  // rdi: elements array's map
701  __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
702  __ j(not_equal, &slow);
703  __ leal(rdi, Operand(rcx, 1));
704  __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
705  __ jmp(&fast_double_without_map_check);
706
707  // Array case: Get the length and the elements array from the JS
708  // array. Check that the array is in fast mode (and writable); if it
709  // is the length is always a smi.
710  __ bind(&array);
711  // rax: value
712  // rdx: receiver (a JSArray)
713  // rcx: index
714  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
715
716  // Check the key against the length in the array, compute the
717  // address to store into and fall through to fast case.
718  __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
719  __ j(below_equal, &extra);
720
721  // Fast case: Do the store.
722  __ bind(&fast_object_with_map_check);
723  // rax: value
724  // rbx: receiver's elements array (a FixedArray)
725  // rcx: index
726  // rdx: receiver (a JSArray)
727  __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
728  __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
729  __ j(not_equal, &fast_double_with_map_check);
730  __ bind(&fast_object_without_map_check);
731  // Smi stores don't require further checks.
732  Label non_smi_value;
733  __ JumpIfNotSmi(rax, &non_smi_value);
734  // It's irrelevant whether array is smi-only or not when writing a smi.
735  __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
736          rax);
737  __ ret(0);
738
739  __ bind(&non_smi_value);
740  // Writing a non-smi, check whether array allows non-smi elements.
741  // r9: receiver's map
742  __ CheckFastObjectElements(r9, &transition_smi_elements);
743  __ bind(&finish_object_store);
744  __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
745          rax);
746  __ movq(rdx, rax);  // Preserve the value which is returned.
747  __ RecordWriteArray(
748      rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
749  __ ret(0);
750
751  __ bind(&fast_double_with_map_check);
752  // Check for fast double array case. If this fails, call through to the
753  // runtime.
754  // rdi: elements array's map
755  __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
756  __ j(not_equal, &slow);
757  __ bind(&fast_double_without_map_check);
758  // If the value is a number, store it as a double in the FastDoubleElements
759  // array.
760  __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
761                                 &transition_double_elements);
762  __ ret(0);
763
764  __ bind(&transition_smi_elements);
765  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
766
767  // Transition the array appropriately depending on the value type.
768  __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
769  __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
770  __ j(not_equal, &non_double_value);
771
772  // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
773  // FAST_DOUBLE_ELEMENTS and complete the store.
774  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
775                                         FAST_DOUBLE_ELEMENTS,
776                                         rbx,
777                                         rdi,
778                                         &slow);
779  ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
780  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
781  __ jmp(&fast_double_without_map_check);
782
783  __ bind(&non_double_value);
784  // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
785  __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
786                                         FAST_ELEMENTS,
787                                         rbx,
788                                         rdi,
789                                         &slow);
790  ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
791  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
792  __ jmp(&finish_object_store);
793
794  __ bind(&transition_double_elements);
795  // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
796  // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
797  // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
798  __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
799  __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
800                                         FAST_ELEMENTS,
801                                         rbx,
802                                         rdi,
803                                         &slow);
804  ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
805  __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
806  __ jmp(&finish_object_store);
807}
808
809
810// The generated code does not accept smi keys.
811// The generated code falls through if both probes miss.
812void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
813                                               int argc,
814                                               Code::Kind kind,
815                                               Code::ExtraICState extra_state) {
816  // ----------- S t a t e -------------
817  // rcx                      : function name
818  // rdx                      : receiver
819  // -----------------------------------
820  Label number, non_number, non_string, boolean, probe, miss;
821
822  // Probe the stub cache.
823  Code::Flags flags = Code::ComputeFlags(kind,
824                                         MONOMORPHIC,
825                                         extra_state,
826                                         NORMAL,
827                                         argc);
828  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
829                                                  rax);
830
831  // If the stub cache probing failed, the receiver might be a value.
832  // For value objects, we use the map of the prototype objects for
833  // the corresponding JSValue for the cache and that is what we need
834  // to probe.
835  //
836  // Check for number.
837  __ JumpIfSmi(rdx, &number);
838  __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx);
839  __ j(not_equal, &non_number);
840  __ bind(&number);
841  StubCompiler::GenerateLoadGlobalFunctionPrototype(
842      masm, Context::NUMBER_FUNCTION_INDEX, rdx);
843  __ jmp(&probe);
844
845  // Check for string.
846  __ bind(&non_number);
847  __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE);
848  __ j(above_equal, &non_string);
849  StubCompiler::GenerateLoadGlobalFunctionPrototype(
850      masm, Context::STRING_FUNCTION_INDEX, rdx);
851  __ jmp(&probe);
852
853  // Check for boolean.
854  __ bind(&non_string);
855  __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
856  __ j(equal, &boolean);
857  __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
858  __ j(not_equal, &miss);
859  __ bind(&boolean);
860  StubCompiler::GenerateLoadGlobalFunctionPrototype(
861      masm, Context::BOOLEAN_FUNCTION_INDEX, rdx);
862
863  // Probe the stub cache for the value object.
864  __ bind(&probe);
865  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
866                                                  no_reg);
867
868  __ bind(&miss);
869}
870
871
872static void GenerateFunctionTailCall(MacroAssembler* masm,
873                                     int argc,
874                                     Label* miss) {
875  // ----------- S t a t e -------------
876  // rcx                    : function name
877  // rdi                    : function
878  // rsp[0]                 : return address
879  // rsp[8]                 : argument argc
880  // rsp[16]                : argument argc - 1
881  // ...
882  // rsp[argc * 8]          : argument 1
883  // rsp[(argc + 1) * 8]    : argument 0 = receiver
884  // -----------------------------------
885  __ JumpIfSmi(rdi, miss);
886  // Check that the value is a JavaScript function.
887  __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
888  __ j(not_equal, miss);
889
890  // Invoke the function.
891  ParameterCount actual(argc);
892  __ InvokeFunction(rdi, actual, JUMP_FUNCTION,
893                    NullCallWrapper(), CALL_AS_METHOD);
894}
895
896
897// The generated code falls through if the call should be handled by runtime.
898void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
899  // ----------- S t a t e -------------
900  // rcx                    : function name
901  // rsp[0]                 : return address
902  // rsp[8]                 : argument argc
903  // rsp[16]                : argument argc - 1
904  // ...
905  // rsp[argc * 8]          : argument 1
906  // rsp[(argc + 1) * 8]    : argument 0 = receiver
907  // -----------------------------------
908  Label miss;
909
910  // Get the receiver of the function from the stack.
911  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
912
913  GenerateStringDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
914
915  // rax: elements
916  // Search the dictionary placing the result in rdi.
917  GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
918
919  GenerateFunctionTailCall(masm, argc, &miss);
920
921  __ bind(&miss);
922}
923
924
925void CallICBase::GenerateMiss(MacroAssembler* masm,
926                              int argc,
927                              IC::UtilityId id,
928                              Code::ExtraICState extra_state) {
929  // ----------- S t a t e -------------
930  // rcx                      : function name
931  // rsp[0]                   : return address
932  // rsp[8]                   : argument argc
933  // rsp[16]                  : argument argc - 1
934  // ...
935  // rsp[argc * 8]            : argument 1
936  // rsp[(argc + 1) * 8]      : argument 0 = receiver
937  // -----------------------------------
938
939  Counters* counters = masm->isolate()->counters();
940  if (id == IC::kCallIC_Miss) {
941    __ IncrementCounter(counters->call_miss(), 1);
942  } else {
943    __ IncrementCounter(counters->keyed_call_miss(), 1);
944  }
945
946  // Get the receiver of the function from the stack; 1 ~ return address.
947  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
948
949  // Enter an internal frame.
950  {
951    FrameScope scope(masm, StackFrame::INTERNAL);
952
953    // Push the receiver and the name of the function.
954    __ push(rdx);
955    __ push(rcx);
956
957    // Call the entry.
958    CEntryStub stub(1);
959    __ Set(rax, 2);
960    __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
961    __ CallStub(&stub);
962
963    // Move result to rdi and exit the internal frame.
964    __ movq(rdi, rax);
965  }
966
967  // Check if the receiver is a global object of some sort.
968  // This can happen only for regular CallIC but not KeyedCallIC.
969  if (id == IC::kCallIC_Miss) {
970    Label invoke, global;
971    __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));  // receiver
972    __ JumpIfSmi(rdx, &invoke);
973    __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
974    __ j(equal, &global);
975    __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
976    __ j(not_equal, &invoke);
977
978    // Patch the receiver on the stack.
979    __ bind(&global);
980    __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
981    __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
982    __ bind(&invoke);
983  }
984
985  // Invoke the function.
986  CallKind call_kind = CallICBase::Contextual::decode(extra_state)
987      ? CALL_AS_FUNCTION
988      : CALL_AS_METHOD;
989  ParameterCount actual(argc);
990  __ InvokeFunction(rdi,
991                    actual,
992                    JUMP_FUNCTION,
993                    NullCallWrapper(),
994                    call_kind);
995}
996
997
998void CallIC::GenerateMegamorphic(MacroAssembler* masm,
999                                 int argc,
1000                                 Code::ExtraICState extra_ic_state) {
1001  // ----------- S t a t e -------------
1002  // rcx                      : function name
1003  // rsp[0]                   : return address
1004  // rsp[8]                   : argument argc
1005  // rsp[16]                  : argument argc - 1
1006  // ...
1007  // rsp[argc * 8]            : argument 1
1008  // rsp[(argc + 1) * 8]      : argument 0 = receiver
1009  // -----------------------------------
1010
1011  // Get the receiver of the function from the stack; 1 ~ return address.
1012  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1013  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
1014  GenerateMiss(masm, argc, extra_ic_state);
1015}
1016
1017
1018void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1019  // ----------- S t a t e -------------
1020  // rcx                      : function name
1021  // rsp[0]                   : return address
1022  // rsp[8]                   : argument argc
1023  // rsp[16]                  : argument argc - 1
1024  // ...
1025  // rsp[argc * 8]            : argument 1
1026  // rsp[(argc + 1) * 8]      : argument 0 = receiver
1027  // -----------------------------------
1028
1029  // Get the receiver of the function from the stack; 1 ~ return address.
1030  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1031
1032  Label do_call, slow_call, slow_load;
1033  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1034  Label index_smi, index_string;
1035
1036  // Check that the key is a smi.
1037  __ JumpIfNotSmi(rcx, &check_string);
1038
1039  __ bind(&index_smi);
1040  // Now the key is known to be a smi. This place is also jumped to from below
1041  // where a numeric string is converted to a smi.
1042
1043  GenerateKeyedLoadReceiverCheck(
1044      masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
1045
1046  GenerateFastArrayLoad(
1047      masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
1048  Counters* counters = masm->isolate()->counters();
1049  __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
1050
1051  __ bind(&do_call);
1052  // receiver in rdx is not used after this point.
1053  // rcx: key
1054  // rdi: function
1055  GenerateFunctionTailCall(masm, argc, &slow_call);
1056
1057  __ bind(&check_number_dictionary);
1058  // rax: elements
1059  // rcx: smi key
1060  // Check whether the elements is a number dictionary.
1061  __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1062                 Heap::kHashTableMapRootIndex);
1063  __ j(not_equal, &slow_load);
1064  __ SmiToInteger32(rbx, rcx);
1065  // ebx: untagged index
1066  __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi);
1067  __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
1068  __ jmp(&do_call);
1069
1070  __ bind(&slow_load);
1071  // This branch is taken when calling KeyedCallIC_Miss is neither required
1072  // nor beneficial.
1073  __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
1074  {
1075    FrameScope scope(masm, StackFrame::INTERNAL);
1076    __ push(rcx);  // save the key
1077    __ push(rdx);  // pass the receiver
1078    __ push(rcx);  // pass the key
1079    __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1080    __ pop(rcx);  // restore the key
1081  }
1082  __ movq(rdi, rax);
1083  __ jmp(&do_call);
1084
1085  __ bind(&check_string);
1086  GenerateKeyStringCheck(masm, rcx, rax, rbx, &index_string, &slow_call);
1087
1088  // The key is known to be a symbol.
1089  // If the receiver is a regular JS object with slow properties then do
1090  // a quick inline probe of the receiver's dictionary.
1091  // Otherwise do the monomorphic cache probe.
1092  GenerateKeyedLoadReceiverCheck(
1093      masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
1094
1095  __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
1096  __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1097                 Heap::kHashTableMapRootIndex);
1098  __ j(not_equal, &lookup_monomorphic_cache);
1099
1100  GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
1101  __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
1102  __ jmp(&do_call);
1103
1104  __ bind(&lookup_monomorphic_cache);
1105  __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
1106  GenerateMonomorphicCacheProbe(masm,
1107                                argc,
1108                                Code::KEYED_CALL_IC,
1109                                Code::kNoExtraICState);
1110  // Fall through on miss.
1111
1112  __ bind(&slow_call);
1113  // This branch is taken if:
1114  // - the receiver requires boxing or access check,
1115  // - the key is neither smi nor symbol,
1116  // - the value loaded is not a function,
1117  // - there is hope that the runtime will create a monomorphic call stub
1118  //   that will get fetched next time.
1119  __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
1120  GenerateMiss(masm, argc);
1121
1122  __ bind(&index_string);
1123  __ IndexFromHash(rbx, rcx);
1124  // Now jump to the place where smi keys are handled.
1125  __ jmp(&index_smi);
1126}
1127
1128
1129void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1130  // ----------- S t a t e -------------
1131  // rcx                      : function name
1132  // rsp[0]                   : return address
1133  // rsp[8]                   : argument argc
1134  // rsp[16]                  : argument argc - 1
1135  // ...
1136  // rsp[argc * 8]            : argument 1
1137  // rsp[(argc + 1) * 8]      : argument 0 = receiver
1138  // -----------------------------------
1139
1140  // Check if the name is a string.
1141  Label miss;
1142  __ JumpIfSmi(rcx, &miss);
1143  Condition cond = masm->IsObjectStringType(rcx, rax, rax);
1144  __ j(NegateCondition(cond), &miss);
1145  CallICBase::GenerateNormal(masm, argc);
1146  __ bind(&miss);
1147  GenerateMiss(masm, argc);
1148}
1149
1150
1151static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
1152                                             Register object,
1153                                             Register key,
1154                                             Register scratch1,
1155                                             Register scratch2,
1156                                             Register scratch3,
1157                                             Label* unmapped_case,
1158                                             Label* slow_case) {
1159  Heap* heap = masm->isolate()->heap();
1160
1161  // Check that the receiver is a JSObject. Because of the elements
1162  // map check later, we do not need to check for interceptors or
1163  // whether it requires access checks.
1164  __ JumpIfSmi(object, slow_case);
1165  // Check that the object is some kind of JSObject.
1166  __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
1167  __ j(below, slow_case);
1168
1169  // Check that the key is a positive smi.
1170  Condition check = masm->CheckNonNegativeSmi(key);
1171  __ j(NegateCondition(check), slow_case);
1172
1173  // Load the elements into scratch1 and check its map. If not, jump
1174  // to the unmapped lookup with the parameter map in scratch1.
1175  Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
1176  __ movq(scratch1, FieldOperand(object, JSObject::kElementsOffset));
1177  __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
1178
1179  // Check if element is in the range of mapped arguments.
1180  __ movq(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
1181  __ SmiSubConstant(scratch2, scratch2, Smi::FromInt(2));
1182  __ cmpq(key, scratch2);
1183  __ j(greater_equal, unmapped_case);
1184
1185  // Load element index and check whether it is the hole.
1186  const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
1187  __ SmiToInteger64(scratch3, key);
1188  __ movq(scratch2, FieldOperand(scratch1,
1189                                 scratch3,
1190                                 times_pointer_size,
1191                                 kHeaderSize));
1192  __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex);
1193  __ j(equal, unmapped_case);
1194
1195  // Load value from context and return it. We can reuse scratch1 because
1196  // we do not jump to the unmapped lookup (which requires the parameter
1197  // map in scratch1).
1198  __ movq(scratch1, FieldOperand(scratch1, FixedArray::kHeaderSize));
1199  __ SmiToInteger64(scratch3, scratch2);
1200  return FieldOperand(scratch1,
1201                      scratch3,
1202                      times_pointer_size,
1203                      Context::kHeaderSize);
1204}
1205
1206
1207static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
1208                                               Register key,
1209                                               Register parameter_map,
1210                                               Register scratch,
1211                                               Label* slow_case) {
1212  // Element is in arguments backing store, which is referenced by the
1213  // second element of the parameter_map. The parameter_map register
1214  // must be loaded with the parameter map of the arguments object and is
1215  // overwritten.
1216  const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
1217  Register backing_store = parameter_map;
1218  __ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
1219  Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
1220  __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
1221  __ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
1222  __ cmpq(key, scratch);
1223  __ j(greater_equal, slow_case);
1224  __ SmiToInteger64(scratch, key);
1225  return FieldOperand(backing_store,
1226                      scratch,
1227                      times_pointer_size,
1228                      FixedArray::kHeaderSize);
1229}
1230
1231
1232void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1233  // ----------- S t a t e -------------
1234  //  -- rax    : key
1235  //  -- rdx    : receiver
1236  //  -- rsp[0]  : return address
1237  // -----------------------------------
1238  Label slow, notin;
1239  Operand mapped_location =
1240      GenerateMappedArgumentsLookup(
1241          masm, rdx, rax, rbx, rcx, rdi, &notin, &slow);
1242  __ movq(rax, mapped_location);
1243  __ Ret();
1244  __ bind(&notin);
1245  // The unmapped lookup expects that the parameter map is in rbx.
1246  Operand unmapped_location =
1247      GenerateUnmappedArgumentsLookup(masm, rax, rbx, rcx, &slow);
1248  __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1249  __ j(equal, &slow);
1250  __ movq(rax, unmapped_location);
1251  __ Ret();
1252  __ bind(&slow);
1253  GenerateMiss(masm, false);
1254}
1255
1256
1257void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1258  // ----------- S t a t e -------------
1259  //  -- rax     : value
1260  //  -- rcx     : key
1261  //  -- rdx     : receiver
1262  //  -- rsp[0]  : return address
1263  // -----------------------------------
1264  Label slow, notin;
1265  Operand mapped_location = GenerateMappedArgumentsLookup(
1266      masm, rdx, rcx, rbx, rdi, r8, &notin, &slow);
1267  __ movq(mapped_location, rax);
1268  __ lea(r9, mapped_location);
1269  __ movq(r8, rax);
1270  __ RecordWrite(rbx,
1271                 r9,
1272                 r8,
1273                 kDontSaveFPRegs,
1274                 EMIT_REMEMBERED_SET,
1275                 INLINE_SMI_CHECK);
1276  __ Ret();
1277  __ bind(&notin);
1278  // The unmapped lookup expects that the parameter map is in rbx.
1279  Operand unmapped_location =
1280      GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow);
1281  __ movq(unmapped_location, rax);
1282  __ lea(r9, unmapped_location);
1283  __ movq(r8, rax);
1284  __ RecordWrite(rbx,
1285                 r9,
1286                 r8,
1287                 kDontSaveFPRegs,
1288                 EMIT_REMEMBERED_SET,
1289                 INLINE_SMI_CHECK);
1290  __ Ret();
1291  __ bind(&slow);
1292  GenerateMiss(masm, false);
1293}
1294
1295
1296void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1297                                             int argc) {
1298  // ----------- S t a t e -------------
1299  // rcx                      : function name
1300  // rsp[0]                   : return address
1301  // rsp[8]                   : argument argc
1302  // rsp[16]                  : argument argc - 1
1303  // ...
1304  // rsp[argc * 8]            : argument 1
1305  // rsp[(argc + 1) * 8]      : argument 0 = receiver
1306  // -----------------------------------
1307  Label slow, notin;
1308  __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1309  Operand mapped_location = GenerateMappedArgumentsLookup(
1310      masm, rdx, rcx, rbx, rax, r8, &notin, &slow);
1311  __ movq(rdi, mapped_location);
1312  GenerateFunctionTailCall(masm, argc, &slow);
1313  __ bind(&notin);
1314  // The unmapped lookup expects that the parameter map is in rbx.
1315  Operand unmapped_location =
1316      GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rax, &slow);
1317  __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1318  __ j(equal, &slow);
1319  __ movq(rdi, unmapped_location);
1320  GenerateFunctionTailCall(masm, argc, &slow);
1321  __ bind(&slow);
1322  GenerateMiss(masm, argc);
1323}
1324
1325
1326void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1327  // ----------- S t a t e -------------
1328  //  -- rax    : receiver
1329  //  -- rcx    : name
1330  //  -- rsp[0] : return address
1331  // -----------------------------------
1332
1333  // Probe the stub cache.
1334  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
1335  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rax, rcx, rbx,
1336                                                  rdx);
1337
1338  // Cache miss: Jump to runtime.
1339  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
1340}
1341
1342
1343void LoadIC::GenerateNormal(MacroAssembler* masm) {
1344  // ----------- S t a t e -------------
1345  //  -- rax    : receiver
1346  //  -- rcx    : name
1347  //  -- rsp[0] : return address
1348  // -----------------------------------
1349  Label miss;
1350
1351  GenerateStringDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
1352
1353  //  rdx: elements
1354  // Search the dictionary placing the result in rax.
1355  GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
1356  __ ret(0);
1357
1358  // Cache miss: Jump to runtime.
1359  __ bind(&miss);
1360  GenerateMiss(masm);
1361}
1362
1363
1364void LoadIC::GenerateMiss(MacroAssembler* masm) {
1365  // ----------- S t a t e -------------
1366  //  -- rax    : receiver
1367  //  -- rcx    : name
1368  //  -- rsp[0] : return address
1369  // -----------------------------------
1370
1371  Counters* counters = masm->isolate()->counters();
1372  __ IncrementCounter(counters->load_miss(), 1);
1373
1374  __ pop(rbx);
1375  __ push(rax);  // receiver
1376  __ push(rcx);  // name
1377  __ push(rbx);  // return address
1378
1379  // Perform tail call to the entry.
1380  ExternalReference ref =
1381      ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
1382  __ TailCallExternalReference(ref, 2, 1);
1383}
1384
1385
1386void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1387  // ----------- S t a t e -------------
1388  //  -- rax    : key
1389  //  -- rdx    : receiver
1390  //  -- rsp[0]  : return address
1391  // -----------------------------------
1392
1393  Counters* counters = masm->isolate()->counters();
1394  __ IncrementCounter(counters->keyed_load_miss(), 1);
1395
1396  __ pop(rbx);
1397  __ push(rdx);  // receiver
1398  __ push(rax);  // name
1399  __ push(rbx);  // return address
1400
1401  // Perform tail call to the entry.
1402  ExternalReference ref = force_generic
1403      ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1404                          masm->isolate())
1405      : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
1406  __ TailCallExternalReference(ref, 2, 1);
1407}
1408
1409
1410void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1411  // ----------- S t a t e -------------
1412  //  -- rax    : key
1413  //  -- rdx    : receiver
1414  //  -- rsp[0]  : return address
1415  // -----------------------------------
1416
1417  __ pop(rbx);
1418  __ push(rdx);  // receiver
1419  __ push(rax);  // name
1420  __ push(rbx);  // return address
1421
1422  // Perform tail call to the entry.
1423  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1424}
1425
1426
1427void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1428                                  StrictModeFlag strict_mode) {
1429  // ----------- S t a t e -------------
1430  //  -- rax    : value
1431  //  -- rcx    : name
1432  //  -- rdx    : receiver
1433  //  -- rsp[0] : return address
1434  // -----------------------------------
1435
1436  // Get the receiver from the stack and probe the stub cache.
1437  Code::Flags flags =
1438      Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
1439  Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
1440                                                  no_reg);
1441
1442  // Cache miss: Jump to runtime.
1443  GenerateMiss(masm);
1444}
1445
1446
1447void StoreIC::GenerateMiss(MacroAssembler* masm) {
1448  // ----------- S t a t e -------------
1449  //  -- rax    : value
1450  //  -- rcx    : name
1451  //  -- rdx    : receiver
1452  //  -- rsp[0] : return address
1453  // -----------------------------------
1454
1455  __ pop(rbx);
1456  __ push(rdx);  // receiver
1457  __ push(rcx);  // name
1458  __ push(rax);  // value
1459  __ push(rbx);  // return address
1460
1461  // Perform tail call to the entry.
1462  ExternalReference ref =
1463      ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
1464  __ TailCallExternalReference(ref, 3, 1);
1465}
1466
1467
1468void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1469  // ----------- S t a t e -------------
1470  //  -- rax    : value
1471  //  -- rcx    : name
1472  //  -- rdx    : receiver
1473  //  -- rsp[0] : return address
1474  // -----------------------------------
1475  //
1476  // This accepts as a receiver anything JSArray::SetElementsLength accepts
1477  // (currently anything except for external arrays which means anything with
1478  // elements of FixedArray type).  Value must be a number, but only smis are
1479  // accepted as the most common case.
1480
1481  Label miss;
1482
1483  Register receiver = rdx;
1484  Register value = rax;
1485  Register scratch = rbx;
1486
1487  // Check that the receiver isn't a smi.
1488  __ JumpIfSmi(receiver, &miss);
1489
1490  // Check that the object is a JS array.
1491  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1492  __ j(not_equal, &miss);
1493
1494  // Check that elements are FixedArray.
1495  // We rely on StoreIC_ArrayLength below to deal with all types of
1496  // fast elements (including COW).
1497  __ movq(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1498  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1499  __ j(not_equal, &miss);
1500
1501  // Check that the array has fast properties, otherwise the length
1502  // property might have been redefined.
1503  __ movq(scratch, FieldOperand(receiver, JSArray::kPropertiesOffset));
1504  __ CompareRoot(FieldOperand(scratch, FixedArray::kMapOffset),
1505                 Heap::kHashTableMapRootIndex);
1506  __ j(equal, &miss);
1507
1508  // Check that value is a smi.
1509  __ JumpIfNotSmi(value, &miss);
1510
1511  // Prepare tail call to StoreIC_ArrayLength.
1512  __ pop(scratch);
1513  __ push(receiver);
1514  __ push(value);
1515  __ push(scratch);  // return address
1516
1517  ExternalReference ref =
1518      ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
1519  __ TailCallExternalReference(ref, 2, 1);
1520
1521  __ bind(&miss);
1522
1523  GenerateMiss(masm);
1524}
1525
1526
1527void StoreIC::GenerateNormal(MacroAssembler* masm) {
1528  // ----------- S t a t e -------------
1529  //  -- rax    : value
1530  //  -- rcx    : name
1531  //  -- rdx    : receiver
1532  //  -- rsp[0] : return address
1533  // -----------------------------------
1534
1535  Label miss;
1536
1537  GenerateStringDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
1538
1539  GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
1540  Counters* counters = masm->isolate()->counters();
1541  __ IncrementCounter(counters->store_normal_hit(), 1);
1542  __ ret(0);
1543
1544  __ bind(&miss);
1545  __ IncrementCounter(counters->store_normal_miss(), 1);
1546  GenerateMiss(masm);
1547}
1548
1549
1550void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1551                                  StrictModeFlag strict_mode) {
1552  // ----------- S t a t e -------------
1553  //  -- rax    : value
1554  //  -- rcx    : name
1555  //  -- rdx    : receiver
1556  //  -- rsp[0] : return address
1557  // -----------------------------------
1558  __ pop(rbx);
1559  __ push(rdx);
1560  __ push(rcx);
1561  __ push(rax);
1562  __ Push(Smi::FromInt(NONE));  // PropertyAttributes
1563  __ Push(Smi::FromInt(strict_mode));
1564  __ push(rbx);  // return address
1565
1566  // Do tail-call to runtime routine.
1567  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1568}
1569
1570
1571void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1572                                              StrictModeFlag strict_mode) {
1573  // ----------- S t a t e -------------
1574  //  -- rax     : value
1575  //  -- rcx     : key
1576  //  -- rdx     : receiver
1577  //  -- rsp[0]  : return address
1578  // -----------------------------------
1579
1580  __ pop(rbx);
1581  __ push(rdx);  // receiver
1582  __ push(rcx);  // key
1583  __ push(rax);  // value
1584  __ Push(Smi::FromInt(NONE));          // PropertyAttributes
1585  __ Push(Smi::FromInt(strict_mode));   // Strict mode.
1586  __ push(rbx);  // return address
1587
1588  // Do tail-call to runtime routine.
1589  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1590}
1591
1592
1593void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1594  // ----------- S t a t e -------------
1595  //  -- rax     : value
1596  //  -- rcx     : key
1597  //  -- rdx     : receiver
1598  //  -- rsp[0]  : return address
1599  // -----------------------------------
1600
1601  __ pop(rbx);
1602  __ push(rdx);  // receiver
1603  __ push(rcx);  // key
1604  __ push(rax);  // value
1605  __ push(rbx);  // return address
1606
1607  // Do tail-call to runtime routine.
1608  ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1609  __ TailCallExternalReference(ref, 3, 1);
1610}
1611
1612
1613void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1614  // ----------- S t a t e -------------
1615  //  -- rax     : value
1616  //  -- rcx     : key
1617  //  -- rdx     : receiver
1618  //  -- rsp[0]  : return address
1619  // -----------------------------------
1620
1621  __ pop(rbx);
1622  __ push(rdx);  // receiver
1623  __ push(rcx);  // key
1624  __ push(rax);  // value
1625  __ push(rbx);  // return address
1626
1627  // Do tail-call to runtime routine.
1628  ExternalReference ref = force_generic
1629    ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1630                        masm->isolate())
1631    : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1632  __ TailCallExternalReference(ref, 3, 1);
1633}
1634
1635
1636void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1637  // ----------- S t a t e -------------
1638  //  -- rbx     : target map
1639  //  -- rdx     : receiver
1640  //  -- rsp[0]  : return address
1641  // -----------------------------------
1642  // Must return the modified receiver in eax.
1643  if (!FLAG_trace_elements_transitions) {
1644    Label fail;
1645    ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
1646    __ movq(rax, rdx);
1647    __ Ret();
1648    __ bind(&fail);
1649  }
1650
1651  __ pop(rbx);
1652  __ push(rdx);
1653  __ push(rbx);  // return address
1654  __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1655}
1656
1657
1658void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1659    MacroAssembler* masm) {
1660  // ----------- S t a t e -------------
1661  //  -- rbx     : target map
1662  //  -- rdx     : receiver
1663  //  -- rsp[0]  : return address
1664  // -----------------------------------
1665  // Must return the modified receiver in eax.
1666  if (!FLAG_trace_elements_transitions) {
1667    Label fail;
1668    ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
1669    __ movq(rax, rdx);
1670    __ Ret();
1671    __ bind(&fail);
1672  }
1673
1674  __ pop(rbx);
1675  __ push(rdx);
1676  __ push(rbx);  // return address
1677  __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1678}
1679
1680
1681#undef __
1682
1683
1684Condition CompareIC::ComputeCondition(Token::Value op) {
1685  switch (op) {
1686    case Token::EQ_STRICT:
1687    case Token::EQ:
1688      return equal;
1689    case Token::LT:
1690      return less;
1691    case Token::GT:
1692      return greater;
1693    case Token::LTE:
1694      return less_equal;
1695    case Token::GTE:
1696      return greater_equal;
1697    default:
1698      UNREACHABLE();
1699      return no_condition;
1700  }
1701}
1702
1703
1704static bool HasInlinedSmiCode(Address address) {
1705  // The address of the instruction following the call.
1706  Address test_instruction_address =
1707      address + Assembler::kCallTargetAddressOffset;
1708
1709  // If the instruction following the call is not a test al, nothing
1710  // was inlined.
1711  return *test_instruction_address == Assembler::kTestAlByte;
1712}
1713
1714
1715void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1716  HandleScope scope;
1717  Handle<Code> rewritten;
1718  State previous_state = GetState();
1719
1720  State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
1721  if (state == GENERIC) {
1722    CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
1723    rewritten = stub.GetCode();
1724  } else {
1725    ICCompareStub stub(op_, state);
1726    if (state == KNOWN_OBJECTS) {
1727      stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
1728    }
1729    rewritten = stub.GetCode();
1730  }
1731  set_target(*rewritten);
1732
1733#ifdef DEBUG
1734  if (FLAG_trace_ic) {
1735    PrintF("[CompareIC (%s->%s)#%s]\n",
1736           GetStateName(previous_state),
1737           GetStateName(state),
1738           Token::Name(op_));
1739  }
1740#endif
1741
1742  // Activate inlined smi code.
1743  if (previous_state == UNINITIALIZED) {
1744    PatchInlinedSmiCode(address());
1745  }
1746}
1747
1748void PatchInlinedSmiCode(Address address) {
1749  // The address of the instruction following the call.
1750  Address test_instruction_address =
1751      address + Assembler::kCallTargetAddressOffset;
1752
1753  // If the instruction following the call is not a test al, nothing
1754  // was inlined.
1755  if (*test_instruction_address != Assembler::kTestAlByte) {
1756    ASSERT(*test_instruction_address == Assembler::kNopByte);
1757    return;
1758  }
1759
1760  Address delta_address = test_instruction_address + 1;
1761  // The delta to the start of the map check instruction and the
1762  // condition code uses at the patched jump.
1763  int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1764  if (FLAG_trace_ic) {
1765    PrintF("[  patching ic at %p, test=%p, delta=%d\n",
1766           address, test_instruction_address, delta);
1767  }
1768
1769  // Patch with a short conditional jump. There must be a
1770  // short jump-if-carry/not-carry at this position.
1771  Address jmp_address = test_instruction_address - delta;
1772  ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
1773         *jmp_address == Assembler::kJcShortOpcode);
1774  Condition cc = *jmp_address == Assembler::kJncShortOpcode
1775      ? not_zero
1776      : zero;
1777  *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
1778}
1779
1780
1781} }  // namespace v8::internal
1782
1783#endif  // V8_TARGET_ARCH_X64
1784