ic-ia32.cc revision 50ef84f5fad2def87d3fbc737bec4a32711fdef4
1// Copyright 2010 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_IA32)
31
32#include "codegen-inl.h"
33#include "ic-inl.h"
34#include "runtime.h"
35#include "stub-cache.h"
36#include "utils.h"
37
38namespace v8 {
39namespace internal {
40
41// ----------------------------------------------------------------------------
42// Static IC stub generators.
43//
44
45#define __ ACCESS_MASM(masm)
46
47
48static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
49                                            Register type,
50                                            Label* global_object) {
51  // Register usage:
52  //   type: holds the receiver instance type on entry.
53  __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
54  __ j(equal, global_object, not_taken);
55  __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
56  __ j(equal, global_object, not_taken);
57  __ cmp(type, JS_GLOBAL_PROXY_TYPE);
58  __ j(equal, global_object, not_taken);
59}
60
61
62// Generated code falls through if the receiver is a regular non-global
63// JS object with slow properties and no interceptors.
64static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
65                                                  Register receiver,
66                                                  Register r0,
67                                                  Register r1,
68                                                  Label* miss) {
69  // Register usage:
70  //   receiver: holds the receiver on entry and is unchanged.
71  //   r0: used to hold receiver instance type.
72  //       Holds the property dictionary on fall through.
73  //   r1: used to hold receivers map.
74
75  // Check that the receiver isn't a smi.
76  __ test(receiver, Immediate(kSmiTagMask));
77  __ j(zero, miss, not_taken);
78
79  // Check that the receiver is a valid JS object.
80  __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
81  __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
82  __ cmp(r0, FIRST_JS_OBJECT_TYPE);
83  __ j(below, miss, not_taken);
84
85  // If this assert fails, we have to check upper bound too.
86  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
87
88  GenerateGlobalInstanceTypeCheck(masm, r0, miss);
89
90  // Check for non-global object that requires access check.
91  __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
92            (1 << Map::kIsAccessCheckNeeded) |
93            (1 << Map::kHasNamedInterceptor));
94  __ j(not_zero, miss, not_taken);
95
96  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
97  __ CheckMap(r0, Factory::hash_table_map(), miss, true);
98}
99
100
101// Probe the string dictionary in the |elements| register. Jump to the
102// |done| label if a property with the given name is found leaving the
103// index into the dictionary in |r0|. Jump to the |miss| label
104// otherwise.
105static void GenerateStringDictionaryProbes(MacroAssembler* masm,
106                                           Label* miss,
107                                           Label* done,
108                                           Register elements,
109                                           Register name,
110                                           Register r0,
111                                           Register r1) {
112  // Compute the capacity mask.
113  const int kCapacityOffset =
114      StringDictionary::kHeaderSize +
115      StringDictionary::kCapacityIndex * kPointerSize;
116  __ mov(r1, FieldOperand(elements, kCapacityOffset));
117  __ shr(r1, kSmiTagSize);  // convert smi to int
118  __ dec(r1);
119
120  // Generate an unrolled loop that performs a few probes before
121  // giving up. Measurements done on Gmail indicate that 2 probes
122  // cover ~93% of loads from dictionaries.
123  static const int kProbes = 4;
124  const int kElementsStartOffset =
125      StringDictionary::kHeaderSize +
126      StringDictionary::kElementsStartIndex * kPointerSize;
127  for (int i = 0; i < kProbes; i++) {
128    // Compute the masked index: (hash + i + i * i) & mask.
129    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
130    __ shr(r0, String::kHashShift);
131    if (i > 0) {
132      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
133    }
134    __ and_(r0, Operand(r1));
135
136    // Scale the index by multiplying by the entry size.
137    ASSERT(StringDictionary::kEntrySize == 3);
138    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
139
140    // Check if the key is identical to the name.
141    __ cmp(name, Operand(elements, r0, times_4,
142                         kElementsStartOffset - kHeapObjectTag));
143    if (i != kProbes - 1) {
144      __ j(equal, done, taken);
145    } else {
146      __ j(not_equal, miss, not_taken);
147    }
148  }
149}
150
151
152
153// Helper function used to load a property from a dictionary backing
154// storage. This function may fail to load a property even though it is
155// in the dictionary, so code at miss_label must always call a backup
156// property load that is complete. This function is safe to call if
157// name is not a symbol, and will jump to the miss_label in that
158// case. The generated code assumes that the receiver has slow
159// properties, is not a global object and does not have interceptors.
160static void GenerateDictionaryLoad(MacroAssembler* masm,
161                                   Label* miss_label,
162                                   Register elements,
163                                   Register name,
164                                   Register r0,
165                                   Register r1,
166                                   Register result) {
167  // Register use:
168  //
169  // elements - holds the property dictionary on entry and is unchanged.
170  //
171  // name - holds the name of the property on entry and is unchanged.
172  //
173  // Scratch registers:
174  //
175  // r0   - used for the index into the property dictionary
176  //
177  // r1   - used to hold the capacity of the property dictionary.
178  //
179  // result - holds the result on exit.
180
181  Label done;
182
183  // Probe the dictionary.
184  GenerateStringDictionaryProbes(masm,
185                                 miss_label,
186                                 &done,
187                                 elements,
188                                 name,
189                                 r0,
190                                 r1);
191
192  // If probing finds an entry in the dictionary, r0 contains the
193  // index into the dictionary. Check that the value is a normal
194  // property.
195  __ bind(&done);
196  const int kElementsStartOffset =
197      StringDictionary::kHeaderSize +
198      StringDictionary::kElementsStartIndex * kPointerSize;
199  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
200  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
201          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
202  __ j(not_zero, miss_label, not_taken);
203
204  // Get the value at the masked, scaled index.
205  const int kValueOffset = kElementsStartOffset + kPointerSize;
206  __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
207}
208
209
210// Helper function used to store a property to a dictionary backing
211// storage. This function may fail to store a property eventhough it
212// is in the dictionary, so code at miss_label must always call a
213// backup property store that is complete. This function is safe to
214// call if name is not a symbol, and will jump to the miss_label in
215// that case. The generated code assumes that the receiver has slow
216// properties, is not a global object and does not have interceptors.
217static void GenerateDictionaryStore(MacroAssembler* masm,
218                                    Label* miss_label,
219                                    Register elements,
220                                    Register name,
221                                    Register value,
222                                    Register r0,
223                                    Register r1) {
224  // Register use:
225  //
226  // elements - holds the property dictionary on entry and is clobbered.
227  //
228  // name - holds the name of the property on entry and is unchanged.
229  //
230  // value - holds the value to store and is unchanged.
231  //
232  // r0 - used for index into the property dictionary and is clobbered.
233  //
234  // r1 - used to hold the capacity of the property dictionary and is clobbered.
235  Label done;
236
237
238  // Probe the dictionary.
239  GenerateStringDictionaryProbes(masm,
240                                 miss_label,
241                                 &done,
242                                 elements,
243                                 name,
244                                 r0,
245                                 r1);
246
247  // If probing finds an entry in the dictionary, r0 contains the
248  // index into the dictionary. Check that the value is a normal
249  // property that is not read only.
250  __ bind(&done);
251  const int kElementsStartOffset =
252      StringDictionary::kHeaderSize +
253      StringDictionary::kElementsStartIndex * kPointerSize;
254  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
255  const int kTypeAndReadOnlyMask
256      = (PropertyDetails::TypeField::mask() |
257         PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
258  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
259          Immediate(kTypeAndReadOnlyMask));
260  __ j(not_zero, miss_label, not_taken);
261
262  // Store the value at the masked, scaled index.
263  const int kValueOffset = kElementsStartOffset + kPointerSize;
264  __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
265  __ mov(Operand(r0, 0), value);
266
267  // Update write barrier. Make sure not to clobber the value.
268  __ mov(r1, value);
269  __ RecordWrite(elements, r0, r1);
270}
271
272
273static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
274                                         Label* miss,
275                                         Register elements,
276                                         Register key,
277                                         Register r0,
278                                         Register r1,
279                                         Register r2,
280                                         Register result) {
281  // Register use:
282  //
283  // elements - holds the slow-case elements of the receiver and is unchanged.
284  //
285  // key      - holds the smi key on entry and is unchanged.
286  //
287  // Scratch registers:
288  //
289  // r0 - holds the untagged key on entry and holds the hash once computed.
290  //
291  // r1 - used to hold the capacity mask of the dictionary
292  //
293  // r2 - used for the index into the dictionary.
294  //
295  // result - holds the result on exit if the load succeeds and we fall through.
296
297  Label done;
298
299  // Compute the hash code from the untagged key.  This must be kept in sync
300  // with ComputeIntegerHash in utils.h.
301  //
302  // hash = ~hash + (hash << 15);
303  __ mov(r1, r0);
304  __ not_(r0);
305  __ shl(r1, 15);
306  __ add(r0, Operand(r1));
307  // hash = hash ^ (hash >> 12);
308  __ mov(r1, r0);
309  __ shr(r1, 12);
310  __ xor_(r0, Operand(r1));
311  // hash = hash + (hash << 2);
312  __ lea(r0, Operand(r0, r0, times_4, 0));
313  // hash = hash ^ (hash >> 4);
314  __ mov(r1, r0);
315  __ shr(r1, 4);
316  __ xor_(r0, Operand(r1));
317  // hash = hash * 2057;
318  __ imul(r0, r0, 2057);
319  // hash = hash ^ (hash >> 16);
320  __ mov(r1, r0);
321  __ shr(r1, 16);
322  __ xor_(r0, Operand(r1));
323
324  // Compute capacity mask.
325  __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
326  __ shr(r1, kSmiTagSize);  // convert smi to int
327  __ dec(r1);
328
329  // Generate an unrolled loop that performs a few probes before giving up.
330  const int kProbes = 4;
331  for (int i = 0; i < kProbes; i++) {
332    // Use r2 for index calculations and keep the hash intact in r0.
333    __ mov(r2, r0);
334    // Compute the masked index: (hash + i + i * i) & mask.
335    if (i > 0) {
336      __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
337    }
338    __ and_(r2, Operand(r1));
339
340    // Scale the index by multiplying by the entry size.
341    ASSERT(NumberDictionary::kEntrySize == 3);
342    __ lea(r2, Operand(r2, r2, times_2, 0));  // r2 = r2 * 3
343
344    // Check if the key matches.
345    __ cmp(key, FieldOperand(elements,
346                             r2,
347                             times_pointer_size,
348                             NumberDictionary::kElementsStartOffset));
349    if (i != (kProbes - 1)) {
350      __ j(equal, &done, taken);
351    } else {
352      __ j(not_equal, miss, not_taken);
353    }
354  }
355
356  __ bind(&done);
357  // Check that the value is a normal propety.
358  const int kDetailsOffset =
359      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
360  ASSERT_EQ(NORMAL, 0);
361  __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
362          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
363  __ j(not_zero, miss);
364
365  // Get the value at the masked, scaled index.
366  const int kValueOffset =
367      NumberDictionary::kElementsStartOffset + kPointerSize;
368  __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
369}
370
371
372// The offset from the inlined patch site to the start of the
373// inlined load instruction.  It is 7 bytes (test eax, imm) plus
374// 6 bytes (jne slow_label).
375const int LoadIC::kOffsetToLoadInstruction = 13;
376
377
378void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
379  // ----------- S t a t e -------------
380  //  -- eax    : receiver
381  //  -- ecx    : name
382  //  -- esp[0] : return address
383  // -----------------------------------
384  Label miss;
385
386  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
387  __ bind(&miss);
388  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
389}
390
391
392void LoadIC::GenerateStringLength(MacroAssembler* masm) {
393  // ----------- S t a t e -------------
394  //  -- eax    : receiver
395  //  -- ecx    : name
396  //  -- esp[0] : return address
397  // -----------------------------------
398  Label miss;
399
400  StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
401  __ bind(&miss);
402  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
403}
404
405
406void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
407  // ----------- S t a t e -------------
408  //  -- eax    : receiver
409  //  -- ecx    : name
410  //  -- esp[0] : return address
411  // -----------------------------------
412  Label miss;
413
414  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
415  __ bind(&miss);
416  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
417}
418
419
420// Checks the receiver for special cases (value type, slow case bits).
421// Falls through for regular JS object.
422static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
423                                           Register receiver,
424                                           Register map,
425                                           int interceptor_bit,
426                                           Label* slow) {
427  // Register use:
428  //   receiver - holds the receiver and is unchanged.
429  // Scratch registers:
430  //   map - used to hold the map of the receiver.
431
432  // Check that the object isn't a smi.
433  __ test(receiver, Immediate(kSmiTagMask));
434  __ j(zero, slow, not_taken);
435
436  // Get the map of the receiver.
437  __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
438
439  // Check bit field.
440  __ test_b(FieldOperand(map, Map::kBitFieldOffset),
441            (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
442  __ j(not_zero, slow, not_taken);
443  // Check that the object is some kind of JS object EXCEPT JS Value type.
444  // In the case that the object is a value-wrapper object,
445  // we enter the runtime system to make sure that indexing
446  // into string objects works as intended.
447  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
448
449  __ CmpInstanceType(map, JS_OBJECT_TYPE);
450  __ j(below, slow, not_taken);
451}
452
453
454// Loads an indexed element from a fast case array.
455static void GenerateFastArrayLoad(MacroAssembler* masm,
456                                  Register receiver,
457                                  Register key,
458                                  Register scratch,
459                                  Register result,
460                                  Label* not_fast_array,
461                                  Label* out_of_range) {
462  // Register use:
463  //   receiver - holds the receiver and is unchanged.
464  //   key - holds the key and is unchanged (must be a smi).
465  // Scratch registers:
466  //   scratch - used to hold elements of the receiver and the loaded value.
467  //   result - holds the result on exit if the load succeeds and
468  //            we fall through.
469
470  __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
471  // Check that the object is in fast mode (not dictionary).
472  __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true);
473  // Check that the key (index) is within bounds.
474  __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
475  __ j(above_equal, out_of_range);
476  // Fast case: Do the load.
477  ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
478  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
479  __ cmp(Operand(scratch), Immediate(Factory::the_hole_value()));
480  // In case the loaded value is the_hole we have to consult GetProperty
481  // to ensure the prototype chain is searched.
482  __ j(equal, out_of_range);
483  if (!result.is(scratch)) {
484    __ mov(result, scratch);
485  }
486}
487
488
489// Checks whether a key is an array index string or a symbol string.
490// Falls through if the key is a symbol.
491static void GenerateKeyStringCheck(MacroAssembler* masm,
492                                   Register key,
493                                   Register map,
494                                   Register hash,
495                                   Label* index_string,
496                                   Label* not_symbol) {
497  // Register use:
498  //   key - holds the key and is unchanged. Assumed to be non-smi.
499  // Scratch registers:
500  //   map - used to hold the map of the key.
501  //   hash - used to hold the hash of the key.
502  __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
503  __ j(above_equal, not_symbol);
504
505  // Is the string an array index, with cached numeric value?
506  __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
507  __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
508  __ j(zero, index_string, not_taken);
509
510  // Is the string a symbol?
511  ASSERT(kSymbolTag != 0);
512  __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
513  __ j(zero, not_symbol, not_taken);
514}
515
516
517// Picks out an array index from the hash field.
518static void GenerateIndexFromHash(MacroAssembler* masm,
519                                  Register key,
520                                  Register hash) {
521  // Register use:
522  //   key - holds the overwritten key on exit.
523  //   hash - holds the key's hash. Clobbered.
524
525  // The assert checks that the constants for the maximum number of digits
526  // for an array index cached in the hash field and the number of bits
527  // reserved for it does not conflict.
528  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
529         (1 << String::kArrayIndexValueBits));
530  // We want the smi-tagged index in key.  kArrayIndexValueMask has zeros in
531  // the low kHashShift bits.
532  ASSERT(String::kHashShift >= kSmiTagSize);
533  __ and_(hash, String::kArrayIndexValueMask);
534  __ shr(hash, String::kHashShift - kSmiTagSize);
535  // Here we actually clobber the key which will be used if calling into
536  // runtime later. However as the new key is the numeric value of a string key
537  // there is no difference in using either key.
538  __ mov(key, hash);
539}
540
541
542void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
543  // ----------- S t a t e -------------
544  //  -- eax    : key
545  //  -- edx    : receiver
546  //  -- esp[0] : return address
547  // -----------------------------------
548  Label slow, check_string, index_smi, index_string;
549  Label check_pixel_array, probe_dictionary, check_number_dictionary;
550
551  // Check that the key is a smi.
552  __ test(eax, Immediate(kSmiTagMask));
553  __ j(not_zero, &check_string, not_taken);
554  __ bind(&index_smi);
555  // Now the key is known to be a smi. This place is also jumped to from
556  // where a numeric string is converted to a smi.
557
558  GenerateKeyedLoadReceiverCheck(
559      masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
560
561  GenerateFastArrayLoad(masm,
562                        edx,
563                        eax,
564                        ecx,
565                        eax,
566                        &check_pixel_array,
567                        &slow);
568  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
569  __ ret(0);
570
571  __ bind(&check_pixel_array);
572  // Check whether the elements is a pixel array.
573  // edx: receiver
574  // eax: key
575  // ecx: elements
576  __ mov(ebx, eax);
577  __ SmiUntag(ebx);
578  __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true);
579  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
580  __ j(above_equal, &slow);
581  __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
582  __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
583  __ SmiTag(eax);
584  __ ret(0);
585
586  __ bind(&check_number_dictionary);
587  // Check whether the elements is a number dictionary.
588  // edx: receiver
589  // ebx: untagged index
590  // eax: key
591  // ecx: elements
592  __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
593  Label slow_pop_receiver;
594  // Push receiver on the stack to free up a register for the dictionary
595  // probing.
596  __ push(edx);
597  GenerateNumberDictionaryLoad(masm,
598                               &slow_pop_receiver,
599                               ecx,
600                               eax,
601                               ebx,
602                               edx,
603                               edi,
604                               eax);
605  // Pop receiver before returning.
606  __ pop(edx);
607  __ ret(0);
608
609  __ bind(&slow_pop_receiver);
610  // Pop the receiver from the stack and jump to runtime.
611  __ pop(edx);
612
613  __ bind(&slow);
614  // Slow case: jump to runtime.
615  // edx: receiver
616  // eax: key
617  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
618  GenerateRuntimeGetProperty(masm);
619
620  __ bind(&check_string);
621  GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
622
623  GenerateKeyedLoadReceiverCheck(
624      masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
625
626  // If the receiver is a fast-case object, check the keyed lookup
627  // cache. Otherwise probe the dictionary.
628  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
629  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
630         Immediate(Factory::hash_table_map()));
631  __ j(equal, &probe_dictionary);
632
633  // Load the map of the receiver, compute the keyed lookup cache hash
634  // based on 32 bits of the map pointer and the string hash.
635  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
636  __ mov(ecx, ebx);
637  __ shr(ecx, KeyedLookupCache::kMapHashShift);
638  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
639  __ shr(edi, String::kHashShift);
640  __ xor_(ecx, Operand(edi));
641  __ and_(ecx, KeyedLookupCache::kCapacityMask);
642
643  // Load the key (consisting of map and symbol) from the cache and
644  // check for match.
645  ExternalReference cache_keys
646      = ExternalReference::keyed_lookup_cache_keys();
647  __ mov(edi, ecx);
648  __ shl(edi, kPointerSizeLog2 + 1);
649  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
650  __ j(not_equal, &slow);
651  __ add(Operand(edi), Immediate(kPointerSize));
652  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
653  __ j(not_equal, &slow);
654
655  // Get field offset and check that it is an in-object property.
656  // edx     : receiver
657  // ebx     : receiver's map
658  // eax     : key
659  // ecx     : lookup cache index
660  ExternalReference cache_field_offsets
661      = ExternalReference::keyed_lookup_cache_field_offsets();
662  __ mov(edi,
663         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
664  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
665  __ sub(edi, Operand(ecx));
666  __ j(above_equal, &slow);
667
668  // Load in-object property.
669  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
670  __ add(ecx, Operand(edi));
671  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
672  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
673  __ ret(0);
674
675  // Do a quick inline probe of the receiver's dictionary, if it
676  // exists.
677  __ bind(&probe_dictionary);
678
679  __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
680  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
681  GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
682
683  GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
684  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
685  __ ret(0);
686
687  __ bind(&index_string);
688  GenerateIndexFromHash(masm, eax, ebx);
689  // Now jump to the place where smi keys are handled.
690  __ jmp(&index_smi);
691}
692
693
694void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
695  // ----------- S t a t e -------------
696  //  -- eax    : key (index)
697  //  -- edx    : receiver
698  //  -- esp[0] : return address
699  // -----------------------------------
700  Label miss;
701  Label index_out_of_range;
702
703  Register receiver = edx;
704  Register index = eax;
705  Register scratch1 = ebx;
706  Register scratch2 = ecx;
707  Register result = eax;
708
709  StringCharAtGenerator char_at_generator(receiver,
710                                          index,
711                                          scratch1,
712                                          scratch2,
713                                          result,
714                                          &miss,  // When not a string.
715                                          &miss,  // When not a number.
716                                          &index_out_of_range,
717                                          STRING_INDEX_IS_ARRAY_INDEX);
718  char_at_generator.GenerateFast(masm);
719  __ ret(0);
720
721  ICRuntimeCallHelper call_helper;
722  char_at_generator.GenerateSlow(masm, call_helper);
723
724  __ bind(&index_out_of_range);
725  __ Set(eax, Immediate(Factory::undefined_value()));
726  __ ret(0);
727
728  __ bind(&miss);
729  GenerateMiss(masm);
730}
731
732
733void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
734                                        ExternalArrayType array_type) {
735  // ----------- S t a t e -------------
736  //  -- eax    : key
737  //  -- edx    : receiver
738  //  -- esp[0] : return address
739  // -----------------------------------
740  Label slow, failed_allocation;
741
742  // Check that the object isn't a smi.
743  __ test(edx, Immediate(kSmiTagMask));
744  __ j(zero, &slow, not_taken);
745
746  // Check that the key is a smi.
747  __ test(eax, Immediate(kSmiTagMask));
748  __ j(not_zero, &slow, not_taken);
749
750  // Get the map of the receiver.
751  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
752  // Check that the receiver does not require access checks.  We need
753  // to check this explicitly since this generic stub does not perform
754  // map checks.
755  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
756            1 << Map::kIsAccessCheckNeeded);
757  __ j(not_zero, &slow, not_taken);
758
759  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
760  __ j(not_equal, &slow, not_taken);
761
762  // Check that the elements array is the appropriate type of
763  // ExternalArray.
764  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
765  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
766  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
767         Immediate(map));
768  __ j(not_equal, &slow, not_taken);
769
770  // eax: key, known to be a smi.
771  // edx: receiver, known to be a JSObject.
772  // ebx: elements object, known to be an external array.
773  // Check that the index is in range.
774  __ mov(ecx, eax);
775  __ SmiUntag(ecx);  // Untag the index.
776  __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
777  // Unsigned comparison catches both negative and too-large values.
778  __ j(above_equal, &slow);
779
780  __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
781  // ebx: base pointer of external storage
782  switch (array_type) {
783    case kExternalByteArray:
784      __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
785      break;
786    case kExternalUnsignedByteArray:
787      __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
788      break;
789    case kExternalShortArray:
790      __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
791      break;
792    case kExternalUnsignedShortArray:
793      __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
794      break;
795    case kExternalIntArray:
796    case kExternalUnsignedIntArray:
797      __ mov(ecx, Operand(ebx, ecx, times_4, 0));
798      break;
799    case kExternalFloatArray:
800      __ fld_s(Operand(ebx, ecx, times_4, 0));
801      break;
802    default:
803      UNREACHABLE();
804      break;
805  }
806
807  // For integer array types:
808  // ecx: value
809  // For floating-point array type:
810  // FP(0): value
811
812  if (array_type == kExternalIntArray ||
813      array_type == kExternalUnsignedIntArray) {
814    // For the Int and UnsignedInt array types, we need to see whether
815    // the value can be represented in a Smi. If not, we need to convert
816    // it to a HeapNumber.
817    Label box_int;
818    if (array_type == kExternalIntArray) {
819      __ cmp(ecx, 0xC0000000);
820      __ j(sign, &box_int);
821    } else {
822      ASSERT_EQ(array_type, kExternalUnsignedIntArray);
823      // The test is different for unsigned int values. Since we need
824      // the value to be in the range of a positive smi, we can't
825      // handle either of the top two bits being set in the value.
826      __ test(ecx, Immediate(0xC0000000));
827      __ j(not_zero, &box_int);
828    }
829
830    __ mov(eax, ecx);
831    __ SmiTag(eax);
832    __ ret(0);
833
834    __ bind(&box_int);
835
836    // Allocate a HeapNumber for the int and perform int-to-double
837    // conversion.
838    if (array_type == kExternalIntArray) {
839      __ push(ecx);
840      __ fild_s(Operand(esp, 0));
841      __ pop(ecx);
842    } else {
843      ASSERT(array_type == kExternalUnsignedIntArray);
844      // Need to zero-extend the value.
845      // There's no fild variant for unsigned values, so zero-extend
846      // to a 64-bit int manually.
847      __ push(Immediate(0));
848      __ push(ecx);
849      __ fild_d(Operand(esp, 0));
850      __ pop(ecx);
851      __ pop(ecx);
852    }
853    // FP(0): value
854    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
855    // Set the value.
856    __ mov(eax, ecx);
857    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
858    __ ret(0);
859  } else if (array_type == kExternalFloatArray) {
860    // For the floating-point array type, we need to always allocate a
861    // HeapNumber.
862    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
863    // Set the value.
864    __ mov(eax, ecx);
865    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
866    __ ret(0);
867  } else {
868    __ mov(eax, ecx);
869    __ SmiTag(eax);
870    __ ret(0);
871  }
872
873  // If we fail allocation of the HeapNumber, we still have a value on
874  // top of the FPU stack. Remove it.
875  __ bind(&failed_allocation);
876  __ ffree();
877  __ fincstp();
878  // Fall through to slow case.
879
880  // Slow case: Jump to runtime.
881  __ bind(&slow);
882  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
883  GenerateRuntimeGetProperty(masm);
884}
885
886
887void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
888  // ----------- S t a t e -------------
889  //  -- eax    : key
890  //  -- edx    : receiver
891  //  -- esp[0] : return address
892  // -----------------------------------
893  Label slow;
894
895  // Check that the receiver isn't a smi.
896  __ test(edx, Immediate(kSmiTagMask));
897  __ j(zero, &slow, not_taken);
898
899  // Check that the key is a smi.
900  __ test(eax, Immediate(kSmiTagMask));
901  __ j(not_zero, &slow, not_taken);
902
903  // Get the map of the receiver.
904  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
905
906  // Check that it has indexed interceptor and access checks
907  // are not enabled for this object.
908  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
909  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
910  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
911  __ j(not_zero, &slow, not_taken);
912
913  // Everything is fine, call runtime.
914  __ pop(ecx);
915  __ push(edx);  // receiver
916  __ push(eax);  // key
917  __ push(ecx);  // return address
918
919  // Perform tail call to the entry.
920  ExternalReference ref = ExternalReference(
921      IC_Utility(kKeyedLoadPropertyWithInterceptor));
922  __ TailCallExternalReference(ref, 2, 1);
923
924  __ bind(&slow);
925  GenerateMiss(masm);
926}
927
928
929void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
930  // ----------- S t a t e -------------
931  //  -- eax    : value
932  //  -- ecx    : key
933  //  -- edx    : receiver
934  //  -- esp[0] : return address
935  // -----------------------------------
936  Label slow, fast, array, extra, check_pixel_array;
937
938  // Check that the object isn't a smi.
939  __ test(edx, Immediate(kSmiTagMask));
940  __ j(zero, &slow, not_taken);
941  // Get the map from the receiver.
942  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
943  // Check that the receiver does not require access checks.  We need
944  // to do this because this generic stub does not perform map checks.
945  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
946            1 << Map::kIsAccessCheckNeeded);
947  __ j(not_zero, &slow, not_taken);
948  // Check that the key is a smi.
949  __ test(ecx, Immediate(kSmiTagMask));
950  __ j(not_zero, &slow, not_taken);
951  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
952  __ j(equal, &array);
953  // Check that the object is some kind of JS object.
954  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
955  __ j(below, &slow, not_taken);
956
957  // Object case: Check key against length in the elements array.
958  // eax: value
959  // edx: JSObject
960  // ecx: key (a smi)
961  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
962  // Check that the object is in fast mode (not dictionary).
963  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
964  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
965  __ j(below, &fast, taken);
966
967  // Slow case: call runtime.
968  __ bind(&slow);
969  GenerateRuntimeSetProperty(masm);
970
971  // Check whether the elements is a pixel array.
972  __ bind(&check_pixel_array);
973  // eax: value
974  // ecx: key (a smi)
975  // edx: receiver
976  // edi: elements array
977  __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
978  // Check that the value is a smi. If a conversion is needed call into the
979  // runtime to convert and clamp.
980  __ test(eax, Immediate(kSmiTagMask));
981  __ j(not_zero, &slow);
982  __ mov(ebx, ecx);
983  __ SmiUntag(ebx);
984  __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
985  __ j(above_equal, &slow);
986  __ mov(ecx, eax);  // Save the value. Key is not longer needed.
987  __ SmiUntag(ecx);
988  {  // Clamp the value to [0..255].
989    Label done;
990    __ test(ecx, Immediate(0xFFFFFF00));
991    __ j(zero, &done);
992    __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
993    __ dec_b(ecx);  // 0 if negative, 255 if positive.
994    __ bind(&done);
995  }
996  __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
997  __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
998  __ ret(0);  // Return value in eax.
999
1000  // Extra capacity case: Check if there is extra capacity to
1001  // perform the store and update the length. Used for adding one
1002  // element to the array by writing to array[array.length].
1003  __ bind(&extra);
1004  // eax: value
1005  // edx: receiver, a JSArray
1006  // ecx: key, a smi.
1007  // edi: receiver->elements, a FixedArray
1008  // flags: compare (ecx, edx.length())
1009  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
1010  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1011  __ j(above_equal, &slow, not_taken);
1012  // Add 1 to receiver->length, and go to fast array write.
1013  __ add(FieldOperand(edx, JSArray::kLengthOffset),
1014         Immediate(Smi::FromInt(1)));
1015  __ jmp(&fast);
1016
1017  // Array case: Get the length and the elements array from the JS
1018  // array. Check that the array is in fast mode; if it is the
1019  // length is always a smi.
1020  __ bind(&array);
1021  // eax: value
1022  // edx: receiver, a JSArray
1023  // ecx: key, a smi.
1024  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
1025  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
1026
1027  // Check the key against the length in the array, compute the
1028  // address to store into and fall through to fast case.
1029  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
1030  __ j(above_equal, &extra, not_taken);
1031
1032  // Fast case: Do the store.
1033  __ bind(&fast);
1034  // eax: value
1035  // ecx: key (a smi)
1036  // edx: receiver
1037  // edi: FixedArray receiver->elements
1038  __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
1039  // Update write barrier for the elements array address.
1040  __ mov(edx, Operand(eax));
1041  __ RecordWrite(edi, 0, edx, ecx);
1042  __ ret(0);
1043}
1044
1045
1046void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
1047                                         ExternalArrayType array_type) {
1048  // ----------- S t a t e -------------
1049  //  -- eax    : value
1050  //  -- ecx    : key
1051  //  -- edx    : receiver
1052  //  -- esp[0] : return address
1053  // -----------------------------------
1054  Label slow, check_heap_number;
1055
1056  // Check that the object isn't a smi.
1057  __ test(edx, Immediate(kSmiTagMask));
1058  __ j(zero, &slow);
1059  // Get the map from the receiver.
1060  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
1061  // Check that the receiver does not require access checks.  We need
1062  // to do this because this generic stub does not perform map checks.
1063  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
1064            1 << Map::kIsAccessCheckNeeded);
1065  __ j(not_zero, &slow);
1066  // Check that the key is a smi.
1067  __ test(ecx, Immediate(kSmiTagMask));
1068  __ j(not_zero, &slow);
1069  // Get the instance type from the map of the receiver.
1070  __ CmpInstanceType(edi, JS_OBJECT_TYPE);
1071  __ j(not_equal, &slow);
1072
1073  // Check that the elements array is the appropriate type of
1074  // ExternalArray.
1075  // eax: value
1076  // edx: receiver, a JSObject
1077  // ecx: key, a smi
1078  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
1079  __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
1080              &slow, true);
1081
1082  // Check that the index is in range.
1083  __ mov(ebx, ecx);
1084  __ SmiUntag(ebx);
1085  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
1086  // Unsigned comparison catches both negative and too-large values.
1087  __ j(above_equal, &slow);
1088
1089  // Handle both smis and HeapNumbers in the fast path. Go to the
1090  // runtime for all other kinds of values.
1091  // eax: value
1092  // edx: receiver
1093  // ecx: key
1094  // edi: elements array
1095  // ebx: untagged index
1096  __ test(eax, Immediate(kSmiTagMask));
1097  __ j(not_equal, &check_heap_number);
1098  // smi case
1099  __ mov(ecx, eax);  // Preserve the value in eax.  Key is no longer needed.
1100  __ SmiUntag(ecx);
1101  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
1102  // ecx: base pointer of external storage
1103  switch (array_type) {
1104    case kExternalByteArray:
1105    case kExternalUnsignedByteArray:
1106      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
1107      break;
1108    case kExternalShortArray:
1109    case kExternalUnsignedShortArray:
1110      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
1111      break;
1112    case kExternalIntArray:
1113    case kExternalUnsignedIntArray:
1114      __ mov(Operand(edi, ebx, times_4, 0), ecx);
1115      break;
1116    case kExternalFloatArray:
1117      // Need to perform int-to-float conversion.
1118      __ push(ecx);
1119      __ fild_s(Operand(esp, 0));
1120      __ pop(ecx);
1121      __ fstp_s(Operand(edi, ebx, times_4, 0));
1122      break;
1123    default:
1124      UNREACHABLE();
1125      break;
1126  }
1127  __ ret(0);  // Return the original value.
1128
1129  __ bind(&check_heap_number);
1130  // eax: value
1131  // edx: receiver
1132  // ecx: key
1133  // edi: elements array
1134  // ebx: untagged index
1135  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1136         Immediate(Factory::heap_number_map()));
1137  __ j(not_equal, &slow);
1138
1139  // The WebGL specification leaves the behavior of storing NaN and
1140  // +/-Infinity into integer arrays basically undefined. For more
1141  // reproducible behavior, convert these to zero.
1142  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
1143  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
1144  // ebx: untagged index
1145  // edi: base pointer of external storage
1146  // top of FPU stack: value
1147  if (array_type == kExternalFloatArray) {
1148    __ fstp_s(Operand(edi, ebx, times_4, 0));
1149    __ ret(0);
1150  } else {
1151    // Need to perform float-to-int conversion.
1152    // Test the top of the FP stack for NaN.
1153    Label is_nan;
1154    __ fucomi(0);
1155    __ j(parity_even, &is_nan);
1156
1157    if (array_type != kExternalUnsignedIntArray) {
1158      __ push(ecx);  // Make room on stack
1159      __ fistp_s(Operand(esp, 0));
1160      __ pop(ecx);
1161    } else {
1162      // fistp stores values as signed integers.
1163      // To represent the entire range, we need to store as a 64-bit
1164      // int and discard the high 32 bits.
1165      __ sub(Operand(esp), Immediate(2 * kPointerSize));
1166      __ fistp_d(Operand(esp, 0));
1167      __ pop(ecx);
1168      __ add(Operand(esp), Immediate(kPointerSize));
1169    }
1170    // ecx: untagged integer value
1171    switch (array_type) {
1172      case kExternalByteArray:
1173      case kExternalUnsignedByteArray:
1174        __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
1175        break;
1176      case kExternalShortArray:
1177      case kExternalUnsignedShortArray:
1178        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
1179        break;
1180      case kExternalIntArray:
1181      case kExternalUnsignedIntArray: {
1182        // We also need to explicitly check for +/-Infinity. These are
1183        // converted to MIN_INT, but we need to be careful not to
1184        // confuse with legal uses of MIN_INT.
1185        Label not_infinity;
1186        // This test would apparently detect both NaN and Infinity,
1187        // but we've already checked for NaN using the FPU hardware
1188        // above.
1189        __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
1190        __ and_(edx, 0x7FF0);
1191        __ cmp(edx, 0x7FF0);
1192        __ j(not_equal, &not_infinity);
1193        __ mov(ecx, 0);
1194        __ bind(&not_infinity);
1195        __ mov(Operand(edi, ebx, times_4, 0), ecx);
1196        break;
1197      }
1198      default:
1199        UNREACHABLE();
1200        break;
1201    }
1202    __ ret(0);  // Return original value.
1203
1204    __ bind(&is_nan);
1205    __ ffree();
1206    __ fincstp();
1207    switch (array_type) {
1208      case kExternalByteArray:
1209      case kExternalUnsignedByteArray:
1210        __ mov_b(Operand(edi, ebx, times_1, 0), 0);
1211        break;
1212      case kExternalShortArray:
1213      case kExternalUnsignedShortArray:
1214        __ xor_(ecx, Operand(ecx));
1215        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
1216        break;
1217      case kExternalIntArray:
1218      case kExternalUnsignedIntArray:
1219        __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
1220        break;
1221      default:
1222        UNREACHABLE();
1223        break;
1224    }
1225    __ ret(0);  // Return the original value.
1226  }
1227
1228  // Slow case: call runtime.
1229  __ bind(&slow);
1230  GenerateRuntimeSetProperty(masm);
1231}
1232
1233
1234// Defined in ic.cc.
1235Object* CallIC_Miss(Arguments args);
1236
1237// The generated code does not accept smi keys.
1238// The generated code falls through if both probes miss.
1239static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
1240                                          int argc,
1241                                          Code::Kind kind) {
1242  // ----------- S t a t e -------------
1243  //  -- ecx                 : name
1244  //  -- edx                 : receiver
1245  // -----------------------------------
1246  Label number, non_number, non_string, boolean, probe, miss;
1247
1248  // Probe the stub cache.
1249  Code::Flags flags =
1250      Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
1251  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
1252
1253  // If the stub cache probing failed, the receiver might be a value.
1254  // For value objects, we use the map of the prototype objects for
1255  // the corresponding JSValue for the cache and that is what we need
1256  // to probe.
1257  //
1258  // Check for number.
1259  __ test(edx, Immediate(kSmiTagMask));
1260  __ j(zero, &number, not_taken);
1261  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
1262  __ j(not_equal, &non_number, taken);
1263  __ bind(&number);
1264  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1265      masm, Context::NUMBER_FUNCTION_INDEX, edx);
1266  __ jmp(&probe);
1267
1268  // Check for string.
1269  __ bind(&non_number);
1270  __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
1271  __ j(above_equal, &non_string, taken);
1272  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1273      masm, Context::STRING_FUNCTION_INDEX, edx);
1274  __ jmp(&probe);
1275
1276  // Check for boolean.
1277  __ bind(&non_string);
1278  __ cmp(edx, Factory::true_value());
1279  __ j(equal, &boolean, not_taken);
1280  __ cmp(edx, Factory::false_value());
1281  __ j(not_equal, &miss, taken);
1282  __ bind(&boolean);
1283  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1284      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
1285
1286  // Probe the stub cache for the value object.
1287  __ bind(&probe);
1288  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1289  __ bind(&miss);
1290}
1291
1292
1293static void GenerateFunctionTailCall(MacroAssembler* masm,
1294                                     int argc,
1295                                     Label* miss) {
1296  // ----------- S t a t e -------------
1297  //  -- ecx                 : name
1298  //  -- edi                 : function
1299  //  -- esp[0]              : return address
1300  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1301  //  -- ...
1302  //  -- esp[(argc + 1) * 4] : receiver
1303  // -----------------------------------
1304
1305  // Check that the result is not a smi.
1306  __ test(edi, Immediate(kSmiTagMask));
1307  __ j(zero, miss, not_taken);
1308
1309  // Check that the value is a JavaScript function, fetching its map into eax.
1310  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
1311  __ j(not_equal, miss, not_taken);
1312
1313  // Invoke the function.
1314  ParameterCount actual(argc);
1315  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1316}
1317
1318// The generated code falls through if the call should be handled by runtime.
1319static void GenerateCallNormal(MacroAssembler* masm, int argc) {
1320  // ----------- S t a t e -------------
1321  //  -- ecx                 : name
1322  //  -- esp[0]              : return address
1323  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1324  //  -- ...
1325  //  -- esp[(argc + 1) * 4] : receiver
1326  // -----------------------------------
1327  Label miss;
1328
1329  // Get the receiver of the function from the stack; 1 ~ return address.
1330  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1331
1332  GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
1333
1334  // eax: elements
1335  // Search the dictionary placing the result in edi.
1336  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
1337  GenerateFunctionTailCall(masm, argc, &miss);
1338
1339  __ bind(&miss);
1340}
1341
1342
1343static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
1344  // ----------- S t a t e -------------
1345  //  -- ecx                 : name
1346  //  -- esp[0]              : return address
1347  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1348  //  -- ...
1349  //  -- esp[(argc + 1) * 4] : receiver
1350  // -----------------------------------
1351
1352  if (id == IC::kCallIC_Miss) {
1353    __ IncrementCounter(&Counters::call_miss, 1);
1354  } else {
1355    __ IncrementCounter(&Counters::keyed_call_miss, 1);
1356  }
1357
1358  // Get the receiver of the function from the stack; 1 ~ return address.
1359  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1360
1361  // Enter an internal frame.
1362  __ EnterInternalFrame();
1363
1364  // Push the receiver and the name of the function.
1365  __ push(edx);
1366  __ push(ecx);
1367
1368  // Call the entry.
1369  CEntryStub stub(1);
1370  __ mov(eax, Immediate(2));
1371  __ mov(ebx, Immediate(ExternalReference(IC_Utility(id))));
1372  __ CallStub(&stub);
1373
1374  // Move result to edi and exit the internal frame.
1375  __ mov(edi, eax);
1376  __ LeaveInternalFrame();
1377
1378  // Check if the receiver is a global object of some sort.
1379  // This can happen only for regular CallIC but not KeyedCallIC.
1380  if (id == IC::kCallIC_Miss) {
1381    Label invoke, global;
1382    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
1383    __ test(edx, Immediate(kSmiTagMask));
1384    __ j(zero, &invoke, not_taken);
1385    __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1386    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1387    __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
1388    __ j(equal, &global);
1389    __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
1390    __ j(not_equal, &invoke);
1391
1392    // Patch the receiver on the stack.
1393    __ bind(&global);
1394    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1395    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1396    __ bind(&invoke);
1397  }
1398
1399  // Invoke the function.
1400  ParameterCount actual(argc);
1401  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1402}
1403
1404
1405void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1406  // ----------- S t a t e -------------
1407  //  -- ecx                 : name
1408  //  -- esp[0]              : return address
1409  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1410  //  -- ...
1411  //  -- esp[(argc + 1) * 4] : receiver
1412  // -----------------------------------
1413
1414  // Get the receiver of the function from the stack; 1 ~ return address.
1415  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1416  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
1417  GenerateMiss(masm, argc);
1418}
1419
1420
1421void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1422  // ----------- S t a t e -------------
1423  //  -- ecx                 : name
1424  //  -- esp[0]              : return address
1425  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1426  //  -- ...
1427  //  -- esp[(argc + 1) * 4] : receiver
1428  // -----------------------------------
1429
1430  GenerateCallNormal(masm, argc);
1431  GenerateMiss(masm, argc);
1432}
1433
1434
1435void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1436  // ----------- S t a t e -------------
1437  //  -- ecx                 : name
1438  //  -- esp[0]              : return address
1439  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1440  //  -- ...
1441  //  -- esp[(argc + 1) * 4] : receiver
1442  // -----------------------------------
1443
1444  GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
1445}
1446
1447
1448void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1449  // ----------- S t a t e -------------
1450  //  -- ecx                 : name
1451  //  -- esp[0]              : return address
1452  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1453  //  -- ...
1454  //  -- esp[(argc + 1) * 4] : receiver
1455  // -----------------------------------
1456
1457  // Get the receiver of the function from the stack; 1 ~ return address.
1458  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1459
1460  Label do_call, slow_call, slow_load, slow_reload_receiver;
1461  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1462  Label index_smi, index_string;
1463
1464  // Check that the key is a smi.
1465  __ test(ecx, Immediate(kSmiTagMask));
1466  __ j(not_zero, &check_string, not_taken);
1467
1468  __ bind(&index_smi);
1469  // Now the key is known to be a smi. This place is also jumped to from
1470  // where a numeric string is converted to a smi.
1471
1472  GenerateKeyedLoadReceiverCheck(
1473      masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
1474
1475  GenerateFastArrayLoad(
1476      masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
1477  __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1);
1478
1479  __ bind(&do_call);
1480  // receiver in edx is not used after this point.
1481  // ecx: key
1482  // edi: function
1483  GenerateFunctionTailCall(masm, argc, &slow_call);
1484
1485  __ bind(&check_number_dictionary);
1486  // eax: elements
1487  // ecx: smi key
1488  // Check whether the elements is a number dictionary.
1489  __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true);
1490  __ mov(ebx, ecx);
1491  __ SmiUntag(ebx);
1492  // ebx: untagged index
1493  // Receiver in edx will be clobbered, need to reload it on miss.
1494  GenerateNumberDictionaryLoad(
1495      masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
1496  __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1);
1497  __ jmp(&do_call);
1498
1499  __ bind(&slow_reload_receiver);
1500  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1501
1502  __ bind(&slow_load);
1503  // This branch is taken when calling KeyedCallIC_Miss is neither required
1504  // nor beneficial.
1505  __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1);
1506  __ EnterInternalFrame();
1507  __ push(ecx);  // save the key
1508  __ push(edx);  // pass the receiver
1509  __ push(ecx);  // pass the key
1510  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1511  __ pop(ecx);  // restore the key
1512  __ LeaveInternalFrame();
1513  __ mov(edi, eax);
1514  __ jmp(&do_call);
1515
1516  __ bind(&check_string);
1517  GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
1518
1519  // The key is known to be a symbol.
1520  // If the receiver is a regular JS object with slow properties then do
1521  // a quick inline probe of the receiver's dictionary.
1522  // Otherwise do the monomorphic cache probe.
1523  GenerateKeyedLoadReceiverCheck(
1524      masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
1525
1526  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
1527  __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
1528
1529  GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
1530  __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
1531  __ jmp(&do_call);
1532
1533  __ bind(&lookup_monomorphic_cache);
1534  __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1);
1535  GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
1536  // Fall through on miss.
1537
1538  __ bind(&slow_call);
1539  // This branch is taken if:
1540  // - the receiver requires boxing or access check,
1541  // - the key is neither smi nor symbol,
1542  // - the value loaded is not a function,
1543  // - there is hope that the runtime will create a monomorphic call stub
1544  //   that will get fetched next time.
1545  __ IncrementCounter(&Counters::keyed_call_generic_slow, 1);
1546  GenerateMiss(masm, argc);
1547
1548  __ bind(&index_string);
1549  GenerateIndexFromHash(masm, ecx, ebx);
1550  // Now jump to the place where smi keys are handled.
1551  __ jmp(&index_smi);
1552}
1553
1554
1555void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1556  // ----------- S t a t e -------------
1557  //  -- ecx                 : name
1558  //  -- esp[0]              : return address
1559  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1560  //  -- ...
1561  //  -- esp[(argc + 1) * 4] : receiver
1562  // -----------------------------------
1563
1564  GenerateCallNormal(masm, argc);
1565  GenerateMiss(masm, argc);
1566}
1567
1568
1569void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1570  // ----------- S t a t e -------------
1571  //  -- ecx                 : name
1572  //  -- esp[0]              : return address
1573  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1574  //  -- ...
1575  //  -- esp[(argc + 1) * 4] : receiver
1576  // -----------------------------------
1577
1578  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
1579}
1580
1581
1582// Defined in ic.cc.
1583Object* LoadIC_Miss(Arguments args);
1584
1585void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1586  // ----------- S t a t e -------------
1587  //  -- eax    : receiver
1588  //  -- ecx    : name
1589  //  -- esp[0] : return address
1590  // -----------------------------------
1591
1592  // Probe the stub cache.
1593  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1594                                         NOT_IN_LOOP,
1595                                         MONOMORPHIC);
1596  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1597
1598  // Cache miss: Jump to runtime.
1599  GenerateMiss(masm);
1600}
1601
1602
1603void LoadIC::GenerateNormal(MacroAssembler* masm) {
1604  // ----------- S t a t e -------------
1605  //  -- eax    : receiver
1606  //  -- ecx    : name
1607  //  -- esp[0] : return address
1608  // -----------------------------------
1609  Label miss;
1610
1611  GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
1612
1613  // edx: elements
1614  // Search the dictionary placing the result in eax.
1615  GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
1616  __ ret(0);
1617
1618  // Cache miss: Jump to runtime.
1619  __ bind(&miss);
1620  GenerateMiss(masm);
1621}
1622
1623
1624void LoadIC::GenerateMiss(MacroAssembler* masm) {
1625  // ----------- S t a t e -------------
1626  //  -- eax    : receiver
1627  //  -- ecx    : name
1628  //  -- esp[0] : return address
1629  // -----------------------------------
1630
1631  __ IncrementCounter(&Counters::load_miss, 1);
1632
1633  __ pop(ebx);
1634  __ push(eax);  // receiver
1635  __ push(ecx);  // name
1636  __ push(ebx);  // return address
1637
1638  // Perform tail call to the entry.
1639  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
1640  __ TailCallExternalReference(ref, 2, 1);
1641}
1642
1643
1644// One byte opcode for test eax,0xXXXXXXXX.
1645static const byte kTestEaxByte = 0xA9;
1646
1647bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1648  // The address of the instruction following the call.
1649  Address test_instruction_address =
1650      address + Assembler::kCallTargetAddressOffset;
1651  // If the instruction following the call is not a test eax, nothing
1652  // was inlined.
1653  if (*test_instruction_address != kTestEaxByte) return false;
1654
1655  Address delta_address = test_instruction_address + 1;
1656  // The delta to the start of the map check instruction.
1657  int delta = *reinterpret_cast<int*>(delta_address);
1658
1659  // The map address is the last 4 bytes of the 7-byte
1660  // operand-immediate compare instruction, so we add 3 to get the
1661  // offset to the last 4 bytes.
1662  Address map_address = test_instruction_address + delta + 3;
1663  *(reinterpret_cast<Object**>(map_address)) = map;
1664
1665  // The offset is in the last 4 bytes of a six byte
1666  // memory-to-register move instruction, so we add 2 to get the
1667  // offset to the last 4 bytes.
1668  Address offset_address =
1669      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1670  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1671  return true;
1672}
1673
1674
1675bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
1676  // The address of the instruction following the call.
1677  Address test_instruction_address =
1678      address + Assembler::kCallTargetAddressOffset;
1679
1680  // If the instruction following the call is not a test eax, nothing
1681  // was inlined.
1682  if (*test_instruction_address != kTestEaxByte) return false;
1683
1684  // Extract the encoded deltas from the test eax instruction.
1685  Address encoded_offsets_address = test_instruction_address + 1;
1686  int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
1687  int delta_to_map_check = -(encoded_offsets & 0xFFFF);
1688  int delta_to_record_write = encoded_offsets >> 16;
1689
1690  // Patch the map to check. The map address is the last 4 bytes of
1691  // the 7-byte operand-immediate compare instruction.
1692  Address map_check_address = test_instruction_address + delta_to_map_check;
1693  Address map_address = map_check_address + 3;
1694  *(reinterpret_cast<Object**>(map_address)) = map;
1695
1696  // Patch the offset in the store instruction. The offset is in the
1697  // last 4 bytes of a six byte register-to-memory move instruction.
1698  Address offset_address =
1699      map_check_address + StoreIC::kOffsetToStoreInstruction + 2;
1700  // The offset should have initial value (kMaxInt - 1), cleared value
1701  // (-1) or we should be clearing the inlined version.
1702  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
1703         *reinterpret_cast<int*>(offset_address) == -1 ||
1704         (offset == 0 && map == Heap::null_value()));
1705  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1706
1707  // Patch the offset in the write-barrier code. The offset is the
1708  // last 4 bytes of a six byte lea instruction.
1709  offset_address = map_check_address + delta_to_record_write + 2;
1710  // The offset should have initial value (kMaxInt), cleared value
1711  // (-1) or we should be clearing the inlined version.
1712  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
1713         *reinterpret_cast<int*>(offset_address) == -1 ||
1714         (offset == 0 && map == Heap::null_value()));
1715  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1716
1717  return true;
1718}
1719
1720
1721static bool PatchInlinedMapCheck(Address address, Object* map) {
1722  Address test_instruction_address =
1723      address + Assembler::kCallTargetAddressOffset;
1724  // The keyed load has a fast inlined case if the IC call instruction
1725  // is immediately followed by a test instruction.
1726  if (*test_instruction_address != kTestEaxByte) return false;
1727
1728  // Fetch the offset from the test instruction to the map cmp
1729  // instruction.  This offset is stored in the last 4 bytes of the 5
1730  // byte test instruction.
1731  Address delta_address = test_instruction_address + 1;
1732  int delta = *reinterpret_cast<int*>(delta_address);
1733  // Compute the map address.  The map address is in the last 4 bytes
1734  // of the 7-byte operand-immediate compare instruction, so we add 3
1735  // to the offset to get the map address.
1736  Address map_address = test_instruction_address + delta + 3;
1737  // Patch the map check.
1738  *(reinterpret_cast<Object**>(map_address)) = map;
1739  return true;
1740}
1741
1742
1743bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1744  return PatchInlinedMapCheck(address, map);
1745}
1746
1747
1748bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1749  return PatchInlinedMapCheck(address, map);
1750}
1751
1752
1753// Defined in ic.cc.
1754Object* KeyedLoadIC_Miss(Arguments args);
1755
1756
1757void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1758  // ----------- S t a t e -------------
1759  //  -- eax    : key
1760  //  -- edx    : receiver
1761  //  -- esp[0] : return address
1762  // -----------------------------------
1763
1764  __ IncrementCounter(&Counters::keyed_load_miss, 1);
1765
1766  __ pop(ebx);
1767  __ push(edx);  // receiver
1768  __ push(eax);  // name
1769  __ push(ebx);  // return address
1770
1771  // Perform tail call to the entry.
1772  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1773  __ TailCallExternalReference(ref, 2, 1);
1774}
1775
1776
1777void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1778  // ----------- S t a t e -------------
1779  //  -- eax    : key
1780  //  -- edx    : receiver
1781  //  -- esp[0] : return address
1782  // -----------------------------------
1783
1784  __ pop(ebx);
1785  __ push(edx);  // receiver
1786  __ push(eax);  // name
1787  __ push(ebx);  // return address
1788
1789  // Perform tail call to the entry.
1790  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1791}
1792
1793
1794void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1795  // ----------- S t a t e -------------
1796  //  -- eax    : value
1797  //  -- ecx    : name
1798  //  -- edx    : receiver
1799  //  -- esp[0] : return address
1800  // -----------------------------------
1801
1802  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1803                                         NOT_IN_LOOP,
1804                                         MONOMORPHIC);
1805  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1806
1807  // Cache miss: Jump to runtime.
1808  GenerateMiss(masm);
1809}
1810
1811
1812void StoreIC::GenerateMiss(MacroAssembler* masm) {
1813  // ----------- S t a t e -------------
1814  //  -- eax    : value
1815  //  -- ecx    : name
1816  //  -- edx    : receiver
1817  //  -- esp[0] : return address
1818  // -----------------------------------
1819
1820  __ pop(ebx);
1821  __ push(edx);
1822  __ push(ecx);
1823  __ push(eax);
1824  __ push(ebx);
1825
1826  // Perform tail call to the entry.
1827  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1828  __ TailCallExternalReference(ref, 3, 1);
1829}
1830
1831
1832// The offset from the inlined patch site to the start of the inlined
1833// store instruction.  It is 7 bytes (test reg, imm) plus 6 bytes (jne
1834// slow_label).
1835const int StoreIC::kOffsetToStoreInstruction = 13;
1836
1837
1838void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1839  // ----------- S t a t e -------------
1840  //  -- eax    : value
1841  //  -- ecx    : name
1842  //  -- edx    : receiver
1843  //  -- esp[0] : return address
1844  // -----------------------------------
1845  //
1846  // This accepts as a receiver anything JSObject::SetElementsLength accepts
1847  // (currently anything except for external and pixel arrays which means
1848  // anything with elements of FixedArray type.), but currently is restricted
1849  // to JSArray.
1850  // Value must be a number, but only smis are accepted as the most common case.
1851
1852  Label miss;
1853
1854  Register receiver = edx;
1855  Register value = eax;
1856  Register scratch = ebx;
1857
1858  // Check that the receiver isn't a smi.
1859  __ test(receiver, Immediate(kSmiTagMask));
1860  __ j(zero, &miss, not_taken);
1861
1862  // Check that the object is a JS array.
1863  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1864  __ j(not_equal, &miss, not_taken);
1865
1866  // Check that elements are FixedArray.
1867  __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1868  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1869  __ j(not_equal, &miss, not_taken);
1870
1871  // Check that value is a smi.
1872  __ test(value, Immediate(kSmiTagMask));
1873  __ j(not_zero, &miss, not_taken);
1874
1875  // Prepare tail call to StoreIC_ArrayLength.
1876  __ pop(scratch);
1877  __ push(receiver);
1878  __ push(value);
1879  __ push(scratch);  // return address
1880
1881  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1882  __ TailCallExternalReference(ref, 2, 1);
1883
1884  __ bind(&miss);
1885
1886  GenerateMiss(masm);
1887}
1888
1889
1890void StoreIC::GenerateNormal(MacroAssembler* masm) {
1891  // ----------- S t a t e -------------
1892  //  -- eax    : value
1893  //  -- ecx    : name
1894  //  -- edx    : receiver
1895  //  -- esp[0] : return address
1896  // -----------------------------------
1897
1898  Label miss, restore_miss;
1899
1900  GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
1901
1902  // A lot of registers are needed for storing to slow case
1903  // objects. Push and restore receiver but rely on
1904  // GenerateDictionaryStore preserving the value and name.
1905  __ push(edx);
1906  GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1907  __ Drop(1);
1908  __ IncrementCounter(&Counters::store_normal_hit, 1);
1909  __ ret(0);
1910
1911  __ bind(&restore_miss);
1912  __ pop(edx);
1913
1914  __ bind(&miss);
1915  __ IncrementCounter(&Counters::store_normal_miss, 1);
1916  GenerateMiss(masm);
1917}
1918
1919
1920// Defined in ic.cc.
1921Object* KeyedStoreIC_Miss(Arguments args);
1922
1923void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1924  // ----------- S t a t e -------------
1925  //  -- eax    : value
1926  //  -- ecx    : key
1927  //  -- edx    : receiver
1928  //  -- esp[0] : return address
1929  // -----------------------------------
1930
1931  __ pop(ebx);
1932  __ push(edx);
1933  __ push(ecx);
1934  __ push(eax);
1935  __ push(ebx);
1936
1937  // Do tail-call to runtime routine.
1938  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
1939}
1940
1941
1942void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1943  // ----------- S t a t e -------------
1944  //  -- eax    : value
1945  //  -- ecx    : key
1946  //  -- edx    : receiver
1947  //  -- esp[0] : return address
1948  // -----------------------------------
1949
1950  __ pop(ebx);
1951  __ push(edx);
1952  __ push(ecx);
1953  __ push(eax);
1954  __ push(ebx);
1955
1956  // Do tail-call to runtime routine.
1957  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1958  __ TailCallExternalReference(ref, 3, 1);
1959}
1960
1961#undef __
1962
1963
1964} }  // namespace v8::internal
1965
1966#endif  // V8_TARGET_ARCH_IA32
1967