ic-ia32.cc revision 0d5e116f6aee03185f237311a943491bb079a768
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.
455// If not_fast_array is NULL, doesn't perform the elements map check.
456static void GenerateFastArrayLoad(MacroAssembler* masm,
457                                  Register receiver,
458                                  Register key,
459                                  Register scratch,
460                                  Register result,
461                                  Label* not_fast_array,
462                                  Label* out_of_range) {
463  // Register use:
464  //   receiver - holds the receiver and is unchanged.
465  //   key - holds the key and is unchanged (must be a smi).
466  // Scratch registers:
467  //   scratch - used to hold elements of the receiver and the loaded value.
468  //   result - holds the result on exit if the load succeeds and
469  //            we fall through.
470
471  __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
472  if (not_fast_array != NULL) {
473    // Check that the object is in fast mode and writable.
474    __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true);
475  } else {
476    __ AssertFastElements(scratch);
477  }
478  // Check that the key (index) is within bounds.
479  __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
480  __ j(above_equal, out_of_range);
481  // Fast case: Do the load.
482  ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
483  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
484  __ cmp(Operand(scratch), Immediate(Factory::the_hole_value()));
485  // In case the loaded value is the_hole we have to consult GetProperty
486  // to ensure the prototype chain is searched.
487  __ j(equal, out_of_range);
488  if (!result.is(scratch)) {
489    __ mov(result, scratch);
490  }
491}
492
493
494// Checks whether a key is an array index string or a symbol string.
495// Falls through if the key is a symbol.
496static void GenerateKeyStringCheck(MacroAssembler* masm,
497                                   Register key,
498                                   Register map,
499                                   Register hash,
500                                   Label* index_string,
501                                   Label* not_symbol) {
502  // Register use:
503  //   key - holds the key and is unchanged. Assumed to be non-smi.
504  // Scratch registers:
505  //   map - used to hold the map of the key.
506  //   hash - used to hold the hash of the key.
507  __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
508  __ j(above_equal, not_symbol);
509
510  // Is the string an array index, with cached numeric value?
511  __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
512  __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
513  __ j(zero, index_string, not_taken);
514
515  // Is the string a symbol?
516  ASSERT(kSymbolTag != 0);
517  __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
518  __ j(zero, not_symbol, not_taken);
519}
520
521
522void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
523  // ----------- S t a t e -------------
524  //  -- eax    : key
525  //  -- edx    : receiver
526  //  -- esp[0] : return address
527  // -----------------------------------
528  Label slow, check_string, index_smi, index_string, property_array_property;
529  Label check_pixel_array, probe_dictionary, check_number_dictionary;
530
531  // Check that the key is a smi.
532  __ test(eax, Immediate(kSmiTagMask));
533  __ j(not_zero, &check_string, not_taken);
534  __ bind(&index_smi);
535  // Now the key is known to be a smi. This place is also jumped to from
536  // where a numeric string is converted to a smi.
537
538  GenerateKeyedLoadReceiverCheck(
539      masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
540
541  // Check the "has fast elements" bit in the receiver's map which is
542  // now in ecx.
543  __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
544            1 << Map::kHasFastElements);
545  __ j(zero, &check_pixel_array, not_taken);
546
547  GenerateFastArrayLoad(masm,
548                        edx,
549                        eax,
550                        ecx,
551                        eax,
552                        NULL,
553                        &slow);
554  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
555  __ ret(0);
556
557  __ bind(&check_pixel_array);
558  // Check whether the elements is a pixel array.
559  // edx: receiver
560  // eax: key
561  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
562  __ mov(ebx, eax);
563  __ SmiUntag(ebx);
564  __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true);
565  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
566  __ j(above_equal, &slow);
567  __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
568  __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
569  __ SmiTag(eax);
570  __ ret(0);
571
572  __ bind(&check_number_dictionary);
573  // Check whether the elements is a number dictionary.
574  // edx: receiver
575  // ebx: untagged index
576  // eax: key
577  // ecx: elements
578  __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
579  Label slow_pop_receiver;
580  // Push receiver on the stack to free up a register for the dictionary
581  // probing.
582  __ push(edx);
583  GenerateNumberDictionaryLoad(masm,
584                               &slow_pop_receiver,
585                               ecx,
586                               eax,
587                               ebx,
588                               edx,
589                               edi,
590                               eax);
591  // Pop receiver before returning.
592  __ pop(edx);
593  __ ret(0);
594
595  __ bind(&slow_pop_receiver);
596  // Pop the receiver from the stack and jump to runtime.
597  __ pop(edx);
598
599  __ bind(&slow);
600  // Slow case: jump to runtime.
601  // edx: receiver
602  // eax: key
603  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
604  GenerateRuntimeGetProperty(masm);
605
606  __ bind(&check_string);
607  GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
608
609  GenerateKeyedLoadReceiverCheck(
610      masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
611
612  // If the receiver is a fast-case object, check the keyed lookup
613  // cache. Otherwise probe the dictionary.
614  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
615  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
616         Immediate(Factory::hash_table_map()));
617  __ j(equal, &probe_dictionary);
618
619  // Load the map of the receiver, compute the keyed lookup cache hash
620  // based on 32 bits of the map pointer and the string hash.
621  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
622  __ mov(ecx, ebx);
623  __ shr(ecx, KeyedLookupCache::kMapHashShift);
624  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
625  __ shr(edi, String::kHashShift);
626  __ xor_(ecx, Operand(edi));
627  __ and_(ecx, KeyedLookupCache::kCapacityMask);
628
629  // Load the key (consisting of map and symbol) from the cache and
630  // check for match.
631  ExternalReference cache_keys
632      = ExternalReference::keyed_lookup_cache_keys();
633  __ mov(edi, ecx);
634  __ shl(edi, kPointerSizeLog2 + 1);
635  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
636  __ j(not_equal, &slow);
637  __ add(Operand(edi), Immediate(kPointerSize));
638  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
639  __ j(not_equal, &slow);
640
641  // Get field offset.
642  // edx     : receiver
643  // ebx     : receiver's map
644  // eax     : key
645  // ecx     : lookup cache index
646  ExternalReference cache_field_offsets
647      = ExternalReference::keyed_lookup_cache_field_offsets();
648  __ mov(edi,
649         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
650  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
651  __ sub(edi, Operand(ecx));
652  __ j(above_equal, &property_array_property);
653
654  // Load in-object property.
655  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
656  __ add(ecx, Operand(edi));
657  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
658  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
659  __ ret(0);
660
661  // Load property array property.
662  __ bind(&property_array_property);
663  __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
664  __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
665                           FixedArray::kHeaderSize));
666  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
667  __ ret(0);
668
669  // Do a quick inline probe of the receiver's dictionary, if it
670  // exists.
671  __ bind(&probe_dictionary);
672
673  __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
674  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
675  GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
676
677  GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
678  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
679  __ ret(0);
680
681  __ bind(&index_string);
682  __ IndexFromHash(ebx, eax);
683  // Now jump to the place where smi keys are handled.
684  __ jmp(&index_smi);
685}
686
687
688void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
689  // ----------- S t a t e -------------
690  //  -- eax    : key (index)
691  //  -- edx    : receiver
692  //  -- esp[0] : return address
693  // -----------------------------------
694  Label miss;
695
696  Register receiver = edx;
697  Register index = eax;
698  Register scratch1 = ebx;
699  Register scratch2 = ecx;
700  Register result = eax;
701
702  StringCharAtGenerator char_at_generator(receiver,
703                                          index,
704                                          scratch1,
705                                          scratch2,
706                                          result,
707                                          &miss,  // When not a string.
708                                          &miss,  // When not a number.
709                                          &miss,  // When index out of range.
710                                          STRING_INDEX_IS_ARRAY_INDEX);
711  char_at_generator.GenerateFast(masm);
712  __ ret(0);
713
714  ICRuntimeCallHelper call_helper;
715  char_at_generator.GenerateSlow(masm, call_helper);
716
717  __ bind(&miss);
718  GenerateMiss(masm);
719}
720
721
722void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
723                                        ExternalArrayType array_type) {
724  // ----------- S t a t e -------------
725  //  -- eax    : key
726  //  -- edx    : receiver
727  //  -- esp[0] : return address
728  // -----------------------------------
729  Label slow, failed_allocation;
730
731  // Check that the object isn't a smi.
732  __ test(edx, Immediate(kSmiTagMask));
733  __ j(zero, &slow, not_taken);
734
735  // Check that the key is a smi.
736  __ test(eax, Immediate(kSmiTagMask));
737  __ j(not_zero, &slow, not_taken);
738
739  // Get the map of the receiver.
740  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
741  // Check that the receiver does not require access checks.  We need
742  // to check this explicitly since this generic stub does not perform
743  // map checks.
744  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
745            1 << Map::kIsAccessCheckNeeded);
746  __ j(not_zero, &slow, not_taken);
747
748  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
749  __ j(not_equal, &slow, not_taken);
750
751  // Check that the elements array is the appropriate type of
752  // ExternalArray.
753  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
754  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
755  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
756         Immediate(map));
757  __ j(not_equal, &slow, not_taken);
758
759  // eax: key, known to be a smi.
760  // edx: receiver, known to be a JSObject.
761  // ebx: elements object, known to be an external array.
762  // Check that the index is in range.
763  __ mov(ecx, eax);
764  __ SmiUntag(ecx);  // Untag the index.
765  __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
766  // Unsigned comparison catches both negative and too-large values.
767  __ j(above_equal, &slow);
768
769  __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
770  // ebx: base pointer of external storage
771  switch (array_type) {
772    case kExternalByteArray:
773      __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
774      break;
775    case kExternalUnsignedByteArray:
776      __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
777      break;
778    case kExternalShortArray:
779      __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
780      break;
781    case kExternalUnsignedShortArray:
782      __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
783      break;
784    case kExternalIntArray:
785    case kExternalUnsignedIntArray:
786      __ mov(ecx, Operand(ebx, ecx, times_4, 0));
787      break;
788    case kExternalFloatArray:
789      __ fld_s(Operand(ebx, ecx, times_4, 0));
790      break;
791    default:
792      UNREACHABLE();
793      break;
794  }
795
796  // For integer array types:
797  // ecx: value
798  // For floating-point array type:
799  // FP(0): value
800
801  if (array_type == kExternalIntArray ||
802      array_type == kExternalUnsignedIntArray) {
803    // For the Int and UnsignedInt array types, we need to see whether
804    // the value can be represented in a Smi. If not, we need to convert
805    // it to a HeapNumber.
806    Label box_int;
807    if (array_type == kExternalIntArray) {
808      __ cmp(ecx, 0xC0000000);
809      __ j(sign, &box_int);
810    } else {
811      ASSERT_EQ(array_type, kExternalUnsignedIntArray);
812      // The test is different for unsigned int values. Since we need
813      // the value to be in the range of a positive smi, we can't
814      // handle either of the top two bits being set in the value.
815      __ test(ecx, Immediate(0xC0000000));
816      __ j(not_zero, &box_int);
817    }
818
819    __ mov(eax, ecx);
820    __ SmiTag(eax);
821    __ ret(0);
822
823    __ bind(&box_int);
824
825    // Allocate a HeapNumber for the int and perform int-to-double
826    // conversion.
827    if (array_type == kExternalIntArray) {
828      __ push(ecx);
829      __ fild_s(Operand(esp, 0));
830      __ pop(ecx);
831    } else {
832      ASSERT(array_type == kExternalUnsignedIntArray);
833      // Need to zero-extend the value.
834      // There's no fild variant for unsigned values, so zero-extend
835      // to a 64-bit int manually.
836      __ push(Immediate(0));
837      __ push(ecx);
838      __ fild_d(Operand(esp, 0));
839      __ pop(ecx);
840      __ pop(ecx);
841    }
842    // FP(0): value
843    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
844    // Set the value.
845    __ mov(eax, ecx);
846    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
847    __ ret(0);
848  } else if (array_type == kExternalFloatArray) {
849    // For the floating-point array type, we need to always allocate a
850    // HeapNumber.
851    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
852    // Set the value.
853    __ mov(eax, ecx);
854    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
855    __ ret(0);
856  } else {
857    __ mov(eax, ecx);
858    __ SmiTag(eax);
859    __ ret(0);
860  }
861
862  // If we fail allocation of the HeapNumber, we still have a value on
863  // top of the FPU stack. Remove it.
864  __ bind(&failed_allocation);
865  __ ffree();
866  __ fincstp();
867  // Fall through to slow case.
868
869  // Slow case: Jump to runtime.
870  __ bind(&slow);
871  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
872  GenerateRuntimeGetProperty(masm);
873}
874
875
876void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
877  // ----------- S t a t e -------------
878  //  -- eax    : key
879  //  -- edx    : receiver
880  //  -- esp[0] : return address
881  // -----------------------------------
882  Label slow;
883
884  // Check that the receiver isn't a smi.
885  __ test(edx, Immediate(kSmiTagMask));
886  __ j(zero, &slow, not_taken);
887
888  // Check that the key is a smi.
889  __ test(eax, Immediate(kSmiTagMask));
890  __ j(not_zero, &slow, not_taken);
891
892  // Get the map of the receiver.
893  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
894
895  // Check that it has indexed interceptor and access checks
896  // are not enabled for this object.
897  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
898  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
899  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
900  __ j(not_zero, &slow, not_taken);
901
902  // Everything is fine, call runtime.
903  __ pop(ecx);
904  __ push(edx);  // receiver
905  __ push(eax);  // key
906  __ push(ecx);  // return address
907
908  // Perform tail call to the entry.
909  ExternalReference ref = ExternalReference(
910      IC_Utility(kKeyedLoadPropertyWithInterceptor));
911  __ TailCallExternalReference(ref, 2, 1);
912
913  __ bind(&slow);
914  GenerateMiss(masm);
915}
916
917
918void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
919  // ----------- S t a t e -------------
920  //  -- eax    : value
921  //  -- ecx    : key
922  //  -- edx    : receiver
923  //  -- esp[0] : return address
924  // -----------------------------------
925  Label slow, fast, array, extra, check_pixel_array;
926
927  // Check that the object isn't a smi.
928  __ test(edx, Immediate(kSmiTagMask));
929  __ j(zero, &slow, not_taken);
930  // Get the map from the receiver.
931  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
932  // Check that the receiver does not require access checks.  We need
933  // to do this because this generic stub does not perform map checks.
934  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
935            1 << Map::kIsAccessCheckNeeded);
936  __ j(not_zero, &slow, not_taken);
937  // Check that the key is a smi.
938  __ test(ecx, Immediate(kSmiTagMask));
939  __ j(not_zero, &slow, not_taken);
940  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
941  __ j(equal, &array);
942  // Check that the object is some kind of JS object.
943  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
944  __ j(below, &slow, not_taken);
945
946  // Object case: Check key against length in the elements array.
947  // eax: value
948  // edx: JSObject
949  // ecx: key (a smi)
950  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
951  // Check that the object is in fast mode and writable.
952  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
953  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
954  __ j(below, &fast, taken);
955
956  // Slow case: call runtime.
957  __ bind(&slow);
958  GenerateRuntimeSetProperty(masm);
959
960  // Check whether the elements is a pixel array.
961  __ bind(&check_pixel_array);
962  // eax: value
963  // ecx: key (a smi)
964  // edx: receiver
965  // edi: elements array
966  __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
967  // Check that the value is a smi. If a conversion is needed call into the
968  // runtime to convert and clamp.
969  __ test(eax, Immediate(kSmiTagMask));
970  __ j(not_zero, &slow);
971  __ mov(ebx, ecx);
972  __ SmiUntag(ebx);
973  __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
974  __ j(above_equal, &slow);
975  __ mov(ecx, eax);  // Save the value. Key is not longer needed.
976  __ SmiUntag(ecx);
977  {  // Clamp the value to [0..255].
978    Label done;
979    __ test(ecx, Immediate(0xFFFFFF00));
980    __ j(zero, &done);
981    __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
982    __ dec_b(ecx);  // 0 if negative, 255 if positive.
983    __ bind(&done);
984  }
985  __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
986  __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
987  __ ret(0);  // Return value in eax.
988
989  // Extra capacity case: Check if there is extra capacity to
990  // perform the store and update the length. Used for adding one
991  // element to the array by writing to array[array.length].
992  __ bind(&extra);
993  // eax: value
994  // edx: receiver, a JSArray
995  // ecx: key, a smi.
996  // edi: receiver->elements, a FixedArray
997  // flags: compare (ecx, edx.length())
998  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
999  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1000  __ j(above_equal, &slow, not_taken);
1001  // Add 1 to receiver->length, and go to fast array write.
1002  __ add(FieldOperand(edx, JSArray::kLengthOffset),
1003         Immediate(Smi::FromInt(1)));
1004  __ jmp(&fast);
1005
1006  // Array case: Get the length and the elements array from the JS
1007  // array. Check that the array is in fast mode (and writable); if it
1008  // is the length is always a smi.
1009  __ bind(&array);
1010  // eax: value
1011  // edx: receiver, a JSArray
1012  // ecx: key, a smi.
1013  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
1014  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
1015
1016  // Check the key against the length in the array, compute the
1017  // address to store into and fall through to fast case.
1018  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
1019  __ j(above_equal, &extra, not_taken);
1020
1021  // Fast case: Do the store.
1022  __ bind(&fast);
1023  // eax: value
1024  // ecx: key (a smi)
1025  // edx: receiver
1026  // edi: FixedArray receiver->elements
1027  __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
1028  // Update write barrier for the elements array address.
1029  __ mov(edx, Operand(eax));
1030  __ RecordWrite(edi, 0, edx, ecx);
1031  __ ret(0);
1032}
1033
1034
1035void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
1036                                         ExternalArrayType array_type) {
1037  // ----------- S t a t e -------------
1038  //  -- eax    : value
1039  //  -- ecx    : key
1040  //  -- edx    : receiver
1041  //  -- esp[0] : return address
1042  // -----------------------------------
1043  Label slow, check_heap_number;
1044
1045  // Check that the object isn't a smi.
1046  __ test(edx, Immediate(kSmiTagMask));
1047  __ j(zero, &slow);
1048  // Get the map from the receiver.
1049  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
1050  // Check that the receiver does not require access checks.  We need
1051  // to do this because this generic stub does not perform map checks.
1052  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
1053            1 << Map::kIsAccessCheckNeeded);
1054  __ j(not_zero, &slow);
1055  // Check that the key is a smi.
1056  __ test(ecx, Immediate(kSmiTagMask));
1057  __ j(not_zero, &slow);
1058  // Get the instance type from the map of the receiver.
1059  __ CmpInstanceType(edi, JS_OBJECT_TYPE);
1060  __ j(not_equal, &slow);
1061
1062  // Check that the elements array is the appropriate type of
1063  // ExternalArray.
1064  // eax: value
1065  // edx: receiver, a JSObject
1066  // ecx: key, a smi
1067  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
1068  __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
1069              &slow, true);
1070
1071  // Check that the index is in range.
1072  __ mov(ebx, ecx);
1073  __ SmiUntag(ebx);
1074  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
1075  // Unsigned comparison catches both negative and too-large values.
1076  __ j(above_equal, &slow);
1077
1078  // Handle both smis and HeapNumbers in the fast path. Go to the
1079  // runtime for all other kinds of values.
1080  // eax: value
1081  // edx: receiver
1082  // ecx: key
1083  // edi: elements array
1084  // ebx: untagged index
1085  __ test(eax, Immediate(kSmiTagMask));
1086  __ j(not_equal, &check_heap_number);
1087  // smi case
1088  __ mov(ecx, eax);  // Preserve the value in eax.  Key is no longer needed.
1089  __ SmiUntag(ecx);
1090  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
1091  // ecx: base pointer of external storage
1092  switch (array_type) {
1093    case kExternalByteArray:
1094    case kExternalUnsignedByteArray:
1095      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
1096      break;
1097    case kExternalShortArray:
1098    case kExternalUnsignedShortArray:
1099      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
1100      break;
1101    case kExternalIntArray:
1102    case kExternalUnsignedIntArray:
1103      __ mov(Operand(edi, ebx, times_4, 0), ecx);
1104      break;
1105    case kExternalFloatArray:
1106      // Need to perform int-to-float conversion.
1107      __ push(ecx);
1108      __ fild_s(Operand(esp, 0));
1109      __ pop(ecx);
1110      __ fstp_s(Operand(edi, ebx, times_4, 0));
1111      break;
1112    default:
1113      UNREACHABLE();
1114      break;
1115  }
1116  __ ret(0);  // Return the original value.
1117
1118  __ bind(&check_heap_number);
1119  // eax: value
1120  // edx: receiver
1121  // ecx: key
1122  // edi: elements array
1123  // ebx: untagged index
1124  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1125         Immediate(Factory::heap_number_map()));
1126  __ j(not_equal, &slow);
1127
1128  // The WebGL specification leaves the behavior of storing NaN and
1129  // +/-Infinity into integer arrays basically undefined. For more
1130  // reproducible behavior, convert these to zero.
1131  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
1132  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
1133  // ebx: untagged index
1134  // edi: base pointer of external storage
1135  // top of FPU stack: value
1136  if (array_type == kExternalFloatArray) {
1137    __ fstp_s(Operand(edi, ebx, times_4, 0));
1138    __ ret(0);
1139  } else {
1140    // Need to perform float-to-int conversion.
1141    // Test the top of the FP stack for NaN.
1142    Label is_nan;
1143    __ fucomi(0);
1144    __ j(parity_even, &is_nan);
1145
1146    if (array_type != kExternalUnsignedIntArray) {
1147      __ push(ecx);  // Make room on stack
1148      __ fistp_s(Operand(esp, 0));
1149      __ pop(ecx);
1150    } else {
1151      // fistp stores values as signed integers.
1152      // To represent the entire range, we need to store as a 64-bit
1153      // int and discard the high 32 bits.
1154      __ sub(Operand(esp), Immediate(2 * kPointerSize));
1155      __ fistp_d(Operand(esp, 0));
1156      __ pop(ecx);
1157      __ add(Operand(esp), Immediate(kPointerSize));
1158    }
1159    // ecx: untagged integer value
1160    switch (array_type) {
1161      case kExternalByteArray:
1162      case kExternalUnsignedByteArray:
1163        __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
1164        break;
1165      case kExternalShortArray:
1166      case kExternalUnsignedShortArray:
1167        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
1168        break;
1169      case kExternalIntArray:
1170      case kExternalUnsignedIntArray: {
1171        // We also need to explicitly check for +/-Infinity. These are
1172        // converted to MIN_INT, but we need to be careful not to
1173        // confuse with legal uses of MIN_INT.
1174        Label not_infinity;
1175        // This test would apparently detect both NaN and Infinity,
1176        // but we've already checked for NaN using the FPU hardware
1177        // above.
1178        __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
1179        __ and_(edx, 0x7FF0);
1180        __ cmp(edx, 0x7FF0);
1181        __ j(not_equal, &not_infinity);
1182        __ mov(ecx, 0);
1183        __ bind(&not_infinity);
1184        __ mov(Operand(edi, ebx, times_4, 0), ecx);
1185        break;
1186      }
1187      default:
1188        UNREACHABLE();
1189        break;
1190    }
1191    __ ret(0);  // Return original value.
1192
1193    __ bind(&is_nan);
1194    __ ffree();
1195    __ fincstp();
1196    switch (array_type) {
1197      case kExternalByteArray:
1198      case kExternalUnsignedByteArray:
1199        __ mov_b(Operand(edi, ebx, times_1, 0), 0);
1200        break;
1201      case kExternalShortArray:
1202      case kExternalUnsignedShortArray:
1203        __ xor_(ecx, Operand(ecx));
1204        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
1205        break;
1206      case kExternalIntArray:
1207      case kExternalUnsignedIntArray:
1208        __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
1209        break;
1210      default:
1211        UNREACHABLE();
1212        break;
1213    }
1214    __ ret(0);  // Return the original value.
1215  }
1216
1217  // Slow case: call runtime.
1218  __ bind(&slow);
1219  GenerateRuntimeSetProperty(masm);
1220}
1221
1222
1223// Defined in ic.cc.
1224Object* CallIC_Miss(Arguments args);
1225
1226// The generated code does not accept smi keys.
1227// The generated code falls through if both probes miss.
1228static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
1229                                          int argc,
1230                                          Code::Kind kind) {
1231  // ----------- S t a t e -------------
1232  //  -- ecx                 : name
1233  //  -- edx                 : receiver
1234  // -----------------------------------
1235  Label number, non_number, non_string, boolean, probe, miss;
1236
1237  // Probe the stub cache.
1238  Code::Flags flags =
1239      Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
1240  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
1241
1242  // If the stub cache probing failed, the receiver might be a value.
1243  // For value objects, we use the map of the prototype objects for
1244  // the corresponding JSValue for the cache and that is what we need
1245  // to probe.
1246  //
1247  // Check for number.
1248  __ test(edx, Immediate(kSmiTagMask));
1249  __ j(zero, &number, not_taken);
1250  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
1251  __ j(not_equal, &non_number, taken);
1252  __ bind(&number);
1253  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1254      masm, Context::NUMBER_FUNCTION_INDEX, edx);
1255  __ jmp(&probe);
1256
1257  // Check for string.
1258  __ bind(&non_number);
1259  __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
1260  __ j(above_equal, &non_string, taken);
1261  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1262      masm, Context::STRING_FUNCTION_INDEX, edx);
1263  __ jmp(&probe);
1264
1265  // Check for boolean.
1266  __ bind(&non_string);
1267  __ cmp(edx, Factory::true_value());
1268  __ j(equal, &boolean, not_taken);
1269  __ cmp(edx, Factory::false_value());
1270  __ j(not_equal, &miss, taken);
1271  __ bind(&boolean);
1272  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1273      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
1274
1275  // Probe the stub cache for the value object.
1276  __ bind(&probe);
1277  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1278  __ bind(&miss);
1279}
1280
1281
1282static void GenerateFunctionTailCall(MacroAssembler* masm,
1283                                     int argc,
1284                                     Label* miss) {
1285  // ----------- S t a t e -------------
1286  //  -- ecx                 : name
1287  //  -- edi                 : function
1288  //  -- esp[0]              : return address
1289  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1290  //  -- ...
1291  //  -- esp[(argc + 1) * 4] : receiver
1292  // -----------------------------------
1293
1294  // Check that the result is not a smi.
1295  __ test(edi, Immediate(kSmiTagMask));
1296  __ j(zero, miss, not_taken);
1297
1298  // Check that the value is a JavaScript function, fetching its map into eax.
1299  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
1300  __ j(not_equal, miss, not_taken);
1301
1302  // Invoke the function.
1303  ParameterCount actual(argc);
1304  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1305}
1306
1307// The generated code falls through if the call should be handled by runtime.
1308static void GenerateCallNormal(MacroAssembler* masm, int argc) {
1309  // ----------- S t a t e -------------
1310  //  -- ecx                 : name
1311  //  -- esp[0]              : return address
1312  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1313  //  -- ...
1314  //  -- esp[(argc + 1) * 4] : receiver
1315  // -----------------------------------
1316  Label miss;
1317
1318  // Get the receiver of the function from the stack; 1 ~ return address.
1319  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1320
1321  GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
1322
1323  // eax: elements
1324  // Search the dictionary placing the result in edi.
1325  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
1326  GenerateFunctionTailCall(masm, argc, &miss);
1327
1328  __ bind(&miss);
1329}
1330
1331
1332static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
1333  // ----------- S t a t e -------------
1334  //  -- ecx                 : name
1335  //  -- esp[0]              : return address
1336  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1337  //  -- ...
1338  //  -- esp[(argc + 1) * 4] : receiver
1339  // -----------------------------------
1340
1341  if (id == IC::kCallIC_Miss) {
1342    __ IncrementCounter(&Counters::call_miss, 1);
1343  } else {
1344    __ IncrementCounter(&Counters::keyed_call_miss, 1);
1345  }
1346
1347  // Get the receiver of the function from the stack; 1 ~ return address.
1348  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1349
1350  // Enter an internal frame.
1351  __ EnterInternalFrame();
1352
1353  // Push the receiver and the name of the function.
1354  __ push(edx);
1355  __ push(ecx);
1356
1357  // Call the entry.
1358  CEntryStub stub(1);
1359  __ mov(eax, Immediate(2));
1360  __ mov(ebx, Immediate(ExternalReference(IC_Utility(id))));
1361  __ CallStub(&stub);
1362
1363  // Move result to edi and exit the internal frame.
1364  __ mov(edi, eax);
1365  __ LeaveInternalFrame();
1366
1367  // Check if the receiver is a global object of some sort.
1368  // This can happen only for regular CallIC but not KeyedCallIC.
1369  if (id == IC::kCallIC_Miss) {
1370    Label invoke, global;
1371    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
1372    __ test(edx, Immediate(kSmiTagMask));
1373    __ j(zero, &invoke, not_taken);
1374    __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1375    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1376    __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
1377    __ j(equal, &global);
1378    __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
1379    __ j(not_equal, &invoke);
1380
1381    // Patch the receiver on the stack.
1382    __ bind(&global);
1383    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1384    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1385    __ bind(&invoke);
1386  }
1387
1388  // Invoke the function.
1389  ParameterCount actual(argc);
1390  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1391}
1392
1393
1394void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1395  // ----------- S t a t e -------------
1396  //  -- ecx                 : name
1397  //  -- esp[0]              : return address
1398  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1399  //  -- ...
1400  //  -- esp[(argc + 1) * 4] : receiver
1401  // -----------------------------------
1402
1403  // Get the receiver of the function from the stack; 1 ~ return address.
1404  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1405  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
1406  GenerateMiss(masm, argc);
1407}
1408
1409
1410void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1411  // ----------- S t a t e -------------
1412  //  -- ecx                 : name
1413  //  -- esp[0]              : return address
1414  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1415  //  -- ...
1416  //  -- esp[(argc + 1) * 4] : receiver
1417  // -----------------------------------
1418
1419  GenerateCallNormal(masm, argc);
1420  GenerateMiss(masm, argc);
1421}
1422
1423
1424void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1425  // ----------- S t a t e -------------
1426  //  -- ecx                 : name
1427  //  -- esp[0]              : return address
1428  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1429  //  -- ...
1430  //  -- esp[(argc + 1) * 4] : receiver
1431  // -----------------------------------
1432
1433  GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
1434}
1435
1436
1437void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1438  // ----------- S t a t e -------------
1439  //  -- ecx                 : name
1440  //  -- esp[0]              : return address
1441  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1442  //  -- ...
1443  //  -- esp[(argc + 1) * 4] : receiver
1444  // -----------------------------------
1445
1446  // Get the receiver of the function from the stack; 1 ~ return address.
1447  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1448
1449  Label do_call, slow_call, slow_load, slow_reload_receiver;
1450  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1451  Label index_smi, index_string;
1452
1453  // Check that the key is a smi.
1454  __ test(ecx, Immediate(kSmiTagMask));
1455  __ j(not_zero, &check_string, not_taken);
1456
1457  __ bind(&index_smi);
1458  // Now the key is known to be a smi. This place is also jumped to from
1459  // where a numeric string is converted to a smi.
1460
1461  GenerateKeyedLoadReceiverCheck(
1462      masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
1463
1464  GenerateFastArrayLoad(
1465      masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
1466  __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1);
1467
1468  __ bind(&do_call);
1469  // receiver in edx is not used after this point.
1470  // ecx: key
1471  // edi: function
1472  GenerateFunctionTailCall(masm, argc, &slow_call);
1473
1474  __ bind(&check_number_dictionary);
1475  // eax: elements
1476  // ecx: smi key
1477  // Check whether the elements is a number dictionary.
1478  __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true);
1479  __ mov(ebx, ecx);
1480  __ SmiUntag(ebx);
1481  // ebx: untagged index
1482  // Receiver in edx will be clobbered, need to reload it on miss.
1483  GenerateNumberDictionaryLoad(
1484      masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
1485  __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1);
1486  __ jmp(&do_call);
1487
1488  __ bind(&slow_reload_receiver);
1489  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1490
1491  __ bind(&slow_load);
1492  // This branch is taken when calling KeyedCallIC_Miss is neither required
1493  // nor beneficial.
1494  __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1);
1495  __ EnterInternalFrame();
1496  __ push(ecx);  // save the key
1497  __ push(edx);  // pass the receiver
1498  __ push(ecx);  // pass the key
1499  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1500  __ pop(ecx);  // restore the key
1501  __ LeaveInternalFrame();
1502  __ mov(edi, eax);
1503  __ jmp(&do_call);
1504
1505  __ bind(&check_string);
1506  GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
1507
1508  // The key is known to be a symbol.
1509  // If the receiver is a regular JS object with slow properties then do
1510  // a quick inline probe of the receiver's dictionary.
1511  // Otherwise do the monomorphic cache probe.
1512  GenerateKeyedLoadReceiverCheck(
1513      masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
1514
1515  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
1516  __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
1517
1518  GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
1519  __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
1520  __ jmp(&do_call);
1521
1522  __ bind(&lookup_monomorphic_cache);
1523  __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1);
1524  GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
1525  // Fall through on miss.
1526
1527  __ bind(&slow_call);
1528  // This branch is taken if:
1529  // - the receiver requires boxing or access check,
1530  // - the key is neither smi nor symbol,
1531  // - the value loaded is not a function,
1532  // - there is hope that the runtime will create a monomorphic call stub
1533  //   that will get fetched next time.
1534  __ IncrementCounter(&Counters::keyed_call_generic_slow, 1);
1535  GenerateMiss(masm, argc);
1536
1537  __ bind(&index_string);
1538  __ IndexFromHash(ebx, ecx);
1539  // Now jump to the place where smi keys are handled.
1540  __ jmp(&index_smi);
1541}
1542
1543
1544void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1545  // ----------- S t a t e -------------
1546  //  -- ecx                 : name
1547  //  -- esp[0]              : return address
1548  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1549  //  -- ...
1550  //  -- esp[(argc + 1) * 4] : receiver
1551  // -----------------------------------
1552
1553  GenerateCallNormal(masm, argc);
1554  GenerateMiss(masm, argc);
1555}
1556
1557
1558void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1559  // ----------- S t a t e -------------
1560  //  -- ecx                 : name
1561  //  -- esp[0]              : return address
1562  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1563  //  -- ...
1564  //  -- esp[(argc + 1) * 4] : receiver
1565  // -----------------------------------
1566
1567  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
1568}
1569
1570
1571// Defined in ic.cc.
1572Object* LoadIC_Miss(Arguments args);
1573
1574void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1575  // ----------- S t a t e -------------
1576  //  -- eax    : receiver
1577  //  -- ecx    : name
1578  //  -- esp[0] : return address
1579  // -----------------------------------
1580
1581  // Probe the stub cache.
1582  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1583                                         NOT_IN_LOOP,
1584                                         MONOMORPHIC);
1585  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1586
1587  // Cache miss: Jump to runtime.
1588  GenerateMiss(masm);
1589}
1590
1591
1592void LoadIC::GenerateNormal(MacroAssembler* masm) {
1593  // ----------- S t a t e -------------
1594  //  -- eax    : receiver
1595  //  -- ecx    : name
1596  //  -- esp[0] : return address
1597  // -----------------------------------
1598  Label miss;
1599
1600  GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
1601
1602  // edx: elements
1603  // Search the dictionary placing the result in eax.
1604  GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
1605  __ ret(0);
1606
1607  // Cache miss: Jump to runtime.
1608  __ bind(&miss);
1609  GenerateMiss(masm);
1610}
1611
1612
1613void LoadIC::GenerateMiss(MacroAssembler* masm) {
1614  // ----------- S t a t e -------------
1615  //  -- eax    : receiver
1616  //  -- ecx    : name
1617  //  -- esp[0] : return address
1618  // -----------------------------------
1619
1620  __ IncrementCounter(&Counters::load_miss, 1);
1621
1622  __ pop(ebx);
1623  __ push(eax);  // receiver
1624  __ push(ecx);  // name
1625  __ push(ebx);  // return address
1626
1627  // Perform tail call to the entry.
1628  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
1629  __ TailCallExternalReference(ref, 2, 1);
1630}
1631
1632
1633// One byte opcode for test eax,0xXXXXXXXX.
1634static const byte kTestEaxByte = 0xA9;
1635
1636bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1637  // The address of the instruction following the call.
1638  Address test_instruction_address =
1639      address + Assembler::kCallTargetAddressOffset;
1640  // If the instruction following the call is not a test eax, nothing
1641  // was inlined.
1642  if (*test_instruction_address != kTestEaxByte) return false;
1643
1644  Address delta_address = test_instruction_address + 1;
1645  // The delta to the start of the map check instruction.
1646  int delta = *reinterpret_cast<int*>(delta_address);
1647
1648  // The map address is the last 4 bytes of the 7-byte
1649  // operand-immediate compare instruction, so we add 3 to get the
1650  // offset to the last 4 bytes.
1651  Address map_address = test_instruction_address + delta + 3;
1652  *(reinterpret_cast<Object**>(map_address)) = map;
1653
1654  // The offset is in the last 4 bytes of a six byte
1655  // memory-to-register move instruction, so we add 2 to get the
1656  // offset to the last 4 bytes.
1657  Address offset_address =
1658      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1659  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1660  return true;
1661}
1662
1663
1664// One byte opcode for mov ecx,0xXXXXXXXX.
1665static const byte kMovEcxByte = 0xB9;
1666
1667bool LoadIC::PatchInlinedContextualLoad(Address address,
1668                                        Object* map,
1669                                        Object* cell) {
1670  // The address of the instruction following the call.
1671  Address mov_instruction_address =
1672      address + Assembler::kCallTargetAddressOffset;
1673  // If the instruction following the call is not a cmp eax, nothing
1674  // was inlined.
1675  if (*mov_instruction_address != kMovEcxByte) return false;
1676
1677  Address delta_address = mov_instruction_address + 1;
1678  // The delta to the start of the map check instruction.
1679  int delta = *reinterpret_cast<int*>(delta_address);
1680
1681  // The map address is the last 4 bytes of the 7-byte
1682  // operand-immediate compare instruction, so we add 3 to get the
1683  // offset to the last 4 bytes.
1684  Address map_address = mov_instruction_address + delta + 3;
1685  *(reinterpret_cast<Object**>(map_address)) = map;
1686
1687  // The cell is in the last 4 bytes of a five byte mov reg, imm32
1688  // instruction, so we add 1 to get the offset to the last 4 bytes.
1689  Address offset_address =
1690      mov_instruction_address + delta + kOffsetToLoadInstruction + 1;
1691  *reinterpret_cast<Object**>(offset_address) = cell;
1692  return true;
1693}
1694
1695
1696bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
1697  // The address of the instruction following the call.
1698  Address test_instruction_address =
1699      address + Assembler::kCallTargetAddressOffset;
1700
1701  // If the instruction following the call is not a test eax, nothing
1702  // was inlined.
1703  if (*test_instruction_address != kTestEaxByte) return false;
1704
1705  // Extract the encoded deltas from the test eax instruction.
1706  Address encoded_offsets_address = test_instruction_address + 1;
1707  int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
1708  int delta_to_map_check = -(encoded_offsets & 0xFFFF);
1709  int delta_to_record_write = encoded_offsets >> 16;
1710
1711  // Patch the map to check. The map address is the last 4 bytes of
1712  // the 7-byte operand-immediate compare instruction.
1713  Address map_check_address = test_instruction_address + delta_to_map_check;
1714  Address map_address = map_check_address + 3;
1715  *(reinterpret_cast<Object**>(map_address)) = map;
1716
1717  // Patch the offset in the store instruction. The offset is in the
1718  // last 4 bytes of a six byte register-to-memory move instruction.
1719  Address offset_address =
1720      map_check_address + StoreIC::kOffsetToStoreInstruction + 2;
1721  // The offset should have initial value (kMaxInt - 1), cleared value
1722  // (-1) or we should be clearing the inlined version.
1723  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
1724         *reinterpret_cast<int*>(offset_address) == -1 ||
1725         (offset == 0 && map == Heap::null_value()));
1726  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1727
1728  // Patch the offset in the write-barrier code. The offset is the
1729  // last 4 bytes of a six byte lea instruction.
1730  offset_address = map_check_address + delta_to_record_write + 2;
1731  // The offset should have initial value (kMaxInt), cleared value
1732  // (-1) or we should be clearing the inlined version.
1733  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
1734         *reinterpret_cast<int*>(offset_address) == -1 ||
1735         (offset == 0 && map == Heap::null_value()));
1736  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1737
1738  return true;
1739}
1740
1741
1742static bool PatchInlinedMapCheck(Address address, Object* map) {
1743  Address test_instruction_address =
1744      address + Assembler::kCallTargetAddressOffset;
1745  // The keyed load has a fast inlined case if the IC call instruction
1746  // is immediately followed by a test instruction.
1747  if (*test_instruction_address != kTestEaxByte) return false;
1748
1749  // Fetch the offset from the test instruction to the map cmp
1750  // instruction.  This offset is stored in the last 4 bytes of the 5
1751  // byte test instruction.
1752  Address delta_address = test_instruction_address + 1;
1753  int delta = *reinterpret_cast<int*>(delta_address);
1754  // Compute the map address.  The map address is in the last 4 bytes
1755  // of the 7-byte operand-immediate compare instruction, so we add 3
1756  // to the offset to get the map address.
1757  Address map_address = test_instruction_address + delta + 3;
1758  // Patch the map check.
1759  *(reinterpret_cast<Object**>(map_address)) = map;
1760  return true;
1761}
1762
1763
1764bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1765  return PatchInlinedMapCheck(address, map);
1766}
1767
1768
1769bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1770  return PatchInlinedMapCheck(address, map);
1771}
1772
1773
1774// Defined in ic.cc.
1775Object* KeyedLoadIC_Miss(Arguments args);
1776
1777
1778void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1779  // ----------- S t a t e -------------
1780  //  -- eax    : key
1781  //  -- edx    : receiver
1782  //  -- esp[0] : return address
1783  // -----------------------------------
1784
1785  __ IncrementCounter(&Counters::keyed_load_miss, 1);
1786
1787  __ pop(ebx);
1788  __ push(edx);  // receiver
1789  __ push(eax);  // name
1790  __ push(ebx);  // return address
1791
1792  // Perform tail call to the entry.
1793  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1794  __ TailCallExternalReference(ref, 2, 1);
1795}
1796
1797
1798void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1799  // ----------- S t a t e -------------
1800  //  -- eax    : key
1801  //  -- edx    : receiver
1802  //  -- esp[0] : return address
1803  // -----------------------------------
1804
1805  __ pop(ebx);
1806  __ push(edx);  // receiver
1807  __ push(eax);  // name
1808  __ push(ebx);  // return address
1809
1810  // Perform tail call to the entry.
1811  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1812}
1813
1814
1815void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1816  // ----------- S t a t e -------------
1817  //  -- eax    : value
1818  //  -- ecx    : name
1819  //  -- edx    : receiver
1820  //  -- esp[0] : return address
1821  // -----------------------------------
1822
1823  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1824                                         NOT_IN_LOOP,
1825                                         MONOMORPHIC);
1826  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1827
1828  // Cache miss: Jump to runtime.
1829  GenerateMiss(masm);
1830}
1831
1832
1833void StoreIC::GenerateMiss(MacroAssembler* masm) {
1834  // ----------- S t a t e -------------
1835  //  -- eax    : value
1836  //  -- ecx    : name
1837  //  -- edx    : receiver
1838  //  -- esp[0] : return address
1839  // -----------------------------------
1840
1841  __ pop(ebx);
1842  __ push(edx);
1843  __ push(ecx);
1844  __ push(eax);
1845  __ push(ebx);
1846
1847  // Perform tail call to the entry.
1848  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1849  __ TailCallExternalReference(ref, 3, 1);
1850}
1851
1852
1853// The offset from the inlined patch site to the start of the inlined
1854// store instruction.  It is 7 bytes (test reg, imm) plus 6 bytes (jne
1855// slow_label).
1856const int StoreIC::kOffsetToStoreInstruction = 13;
1857
1858
1859void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1860  // ----------- S t a t e -------------
1861  //  -- eax    : value
1862  //  -- ecx    : name
1863  //  -- edx    : receiver
1864  //  -- esp[0] : return address
1865  // -----------------------------------
1866  //
1867  // This accepts as a receiver anything JSObject::SetElementsLength accepts
1868  // (currently anything except for external and pixel arrays which means
1869  // anything with elements of FixedArray type.), but currently is restricted
1870  // to JSArray.
1871  // Value must be a number, but only smis are accepted as the most common case.
1872
1873  Label miss;
1874
1875  Register receiver = edx;
1876  Register value = eax;
1877  Register scratch = ebx;
1878
1879  // Check that the receiver isn't a smi.
1880  __ test(receiver, Immediate(kSmiTagMask));
1881  __ j(zero, &miss, not_taken);
1882
1883  // Check that the object is a JS array.
1884  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1885  __ j(not_equal, &miss, not_taken);
1886
1887  // Check that elements are FixedArray.
1888  // We rely on StoreIC_ArrayLength below to deal with all types of
1889  // fast elements (including COW).
1890  __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1891  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1892  __ j(not_equal, &miss, not_taken);
1893
1894  // Check that value is a smi.
1895  __ test(value, Immediate(kSmiTagMask));
1896  __ j(not_zero, &miss, not_taken);
1897
1898  // Prepare tail call to StoreIC_ArrayLength.
1899  __ pop(scratch);
1900  __ push(receiver);
1901  __ push(value);
1902  __ push(scratch);  // return address
1903
1904  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1905  __ TailCallExternalReference(ref, 2, 1);
1906
1907  __ bind(&miss);
1908
1909  GenerateMiss(masm);
1910}
1911
1912
1913void StoreIC::GenerateNormal(MacroAssembler* masm) {
1914  // ----------- S t a t e -------------
1915  //  -- eax    : value
1916  //  -- ecx    : name
1917  //  -- edx    : receiver
1918  //  -- esp[0] : return address
1919  // -----------------------------------
1920
1921  Label miss, restore_miss;
1922
1923  GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
1924
1925  // A lot of registers are needed for storing to slow case
1926  // objects. Push and restore receiver but rely on
1927  // GenerateDictionaryStore preserving the value and name.
1928  __ push(edx);
1929  GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1930  __ Drop(1);
1931  __ IncrementCounter(&Counters::store_normal_hit, 1);
1932  __ ret(0);
1933
1934  __ bind(&restore_miss);
1935  __ pop(edx);
1936
1937  __ bind(&miss);
1938  __ IncrementCounter(&Counters::store_normal_miss, 1);
1939  GenerateMiss(masm);
1940}
1941
1942
1943// Defined in ic.cc.
1944Object* KeyedStoreIC_Miss(Arguments args);
1945
1946void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1947  // ----------- S t a t e -------------
1948  //  -- eax    : value
1949  //  -- ecx    : key
1950  //  -- edx    : receiver
1951  //  -- esp[0] : return address
1952  // -----------------------------------
1953
1954  __ pop(ebx);
1955  __ push(edx);
1956  __ push(ecx);
1957  __ push(eax);
1958  __ push(ebx);
1959
1960  // Do tail-call to runtime routine.
1961  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
1962}
1963
1964
1965void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1966  // ----------- S t a t e -------------
1967  //  -- eax    : value
1968  //  -- ecx    : key
1969  //  -- edx    : receiver
1970  //  -- esp[0] : return address
1971  // -----------------------------------
1972
1973  __ pop(ebx);
1974  __ push(edx);
1975  __ push(ecx);
1976  __ push(eax);
1977  __ push(ebx);
1978
1979  // Do tail-call to runtime routine.
1980  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1981  __ TailCallExternalReference(ref, 3, 1);
1982}
1983
1984#undef __
1985
1986
1987} }  // namespace v8::internal
1988
1989#endif  // V8_TARGET_ARCH_IA32
1990