ic-ia32.cc revision bb769b257e753aafcbd96767abb2abc645eaa20c
17f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Copyright 2010 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Redistribution and use in source and binary forms, with or without
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// modification, are permitted provided that the following conditions are
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// met:
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions of source code must retain the above copyright
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       notice, this list of conditions and the following disclaimer.
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Redistributions in binary form must reproduce the above
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       copyright notice, this list of conditions and the following
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       disclaimer in the documentation and/or other materials provided
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       with the distribution.
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//     * Neither the name of Google Inc. nor the names of its
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       contributors may be used to endorse or promote products derived
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//       from this software without specific prior written permission.
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#if defined(V8_TARGET_ARCH_IA32)
31f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h"
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "runtime.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "stub-cache.h"
36d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "utils.h"
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ----------------------------------------------------------------------------
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Static IC stub generators.
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
488defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
498defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                            Register type,
508defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                            Label* global_object) {
518defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register usage:
528defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   type: holds the receiver instance type on entry.
538defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
548defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(equal, global_object, not_taken);
558defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
568defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(equal, global_object, not_taken);
578defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(type, JS_GLOBAL_PROXY_TYPE);
588defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(equal, global_object, not_taken);
598defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
628defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Generated code falls through if the receiver is a regular non-global
638defd9ff6930b4e24729971a61cf7469daf119beSteve Block// JS object with slow properties and no interceptors.
648defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
658defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Register receiver,
668defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Register r0,
678defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Register r1,
688defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Label* miss) {
698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register usage:
708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   receiver: holds the receiver on entry and is unchanged.
718defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   r0: used to hold receiver instance type.
728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //       Holds the property dictionary on fall through.
738defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   r1: used to hold receivers map.
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check that the receiver isn't a smi.
768defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test(receiver, Immediate(kSmiTagMask));
778defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(zero, miss, not_taken);
788defd9ff6930b4e24729971a61cf7469daf119beSteve Block
798defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check that the receiver is a valid JS object.
808defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
818defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
828defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(r0, FIRST_JS_OBJECT_TYPE);
838defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(below, miss, not_taken);
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
858defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If this assert fails, we have to check upper bound too.
868defd9ff6930b4e24729971a61cf7469daf119beSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
888defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateGlobalInstanceTypeCheck(masm, r0, miss);
898defd9ff6930b4e24729971a61cf7469daf119beSteve Block
908defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check for non-global object that requires access check.
918defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
928defd9ff6930b4e24729971a61cf7469daf119beSteve Block            (1 << Map::kIsAccessCheckNeeded) |
938defd9ff6930b4e24729971a61cf7469daf119beSteve Block            (1 << Map::kHasNamedInterceptor));
948defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_zero, miss, not_taken);
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
96402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
978defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ CheckMap(r0, Factory::hash_table_map(), miss, true);
988defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
99e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1018defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Probe the string dictionary in the |elements| register. Jump to the
1028defd9ff6930b4e24729971a61cf7469daf119beSteve Block// |done| label if a property with the given name is found leaving the
1038defd9ff6930b4e24729971a61cf7469daf119beSteve Block// index into the dictionary in |r0|. Jump to the |miss| label
1048defd9ff6930b4e24729971a61cf7469daf119beSteve Block// otherwise.
1058defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateStringDictionaryProbes(MacroAssembler* masm,
1068defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Label* miss,
1078defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Label* done,
1088defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register elements,
1098defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register name,
1108defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register r0,
1118defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register r1) {
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the capacity mask.
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kCapacityOffset =
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kCapacityIndex * kPointerSize;
1168defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r1, FieldOperand(elements, kCapacityOffset));
1178defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ shr(r1, kSmiTagSize);  // convert smi to int
1188defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ dec(r1);
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate an unrolled loop that performs a few probes before
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // giving up. Measurements done on Gmail indicate that 2 probes
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // cover ~93% of loads from dictionaries.
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kProbes = 4;
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kElementsStartOffset =
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kProbes; i++) {
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the masked index: (hash + i + i * i) & mask.
1298defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
1308defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ shr(r0, String::kHashShift);
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i > 0) {
1328defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1348defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ and_(r0, Operand(r1));
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Scale the index by multiplying by the entry size.
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(StringDictionary::kEntrySize == 3);
1388defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if the key is identical to the name.
1418defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(name, Operand(elements, r0, times_4,
1428defd9ff6930b4e24729971a61cf7469daf119beSteve Block                         kElementsStartOffset - kHeapObjectTag));
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i != kProbes - 1) {
1448defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(equal, done, taken);
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1468defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(not_equal, miss, not_taken);
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1498defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
1508defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1518defd9ff6930b4e24729971a61cf7469daf119beSteve Block
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1538defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Helper function used to load a property from a dictionary backing
1548defd9ff6930b4e24729971a61cf7469daf119beSteve Block// storage. This function may fail to load a property even though it is
1558defd9ff6930b4e24729971a61cf7469daf119beSteve Block// in the dictionary, so code at miss_label must always call a backup
1568defd9ff6930b4e24729971a61cf7469daf119beSteve Block// property load that is complete. This function is safe to call if
1578defd9ff6930b4e24729971a61cf7469daf119beSteve Block// name is not a symbol, and will jump to the miss_label in that
1588defd9ff6930b4e24729971a61cf7469daf119beSteve Block// case. The generated code assumes that the receiver has slow
1598defd9ff6930b4e24729971a61cf7469daf119beSteve Block// properties, is not a global object and does not have interceptors.
1608defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateDictionaryLoad(MacroAssembler* masm,
1618defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Label* miss_label,
1628defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register elements,
1638defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register name,
1648defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register r0,
1658defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register r1,
1668defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register result) {
1678defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register use:
1688defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // elements - holds the property dictionary on entry and is unchanged.
1708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1718defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // name - holds the name of the property on entry and is unchanged.
1728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1738defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Scratch registers:
1748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r0   - used for the index into the property dictionary
1768defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1778defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r1   - used to hold the capacity of the property dictionary.
1788defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1798defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // result - holds the result on exit.
1808defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1818defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label done;
1828defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1838defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Probe the dictionary.
1848defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryProbes(masm,
1858defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 miss_label,
1868defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 &done,
1878defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 elements,
1888defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 name,
1898defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r0,
1908defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r1);
1918defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1928defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If probing finds an entry in the dictionary, r0 contains the
1938defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // index into the dictionary. Check that the value is a normal
1948defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // property.
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
1968defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kElementsStartOffset =
1978defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kHeaderSize +
1988defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
2008defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, miss_label, not_taken);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the value at the masked, scaled index.
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kValueOffset = kElementsStartOffset + kPointerSize;
2068defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
2078defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
2088defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2098defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2108defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Helper function used to store a property to a dictionary backing
2118defd9ff6930b4e24729971a61cf7469daf119beSteve Block// storage. This function may fail to store a property eventhough it
2128defd9ff6930b4e24729971a61cf7469daf119beSteve Block// is in the dictionary, so code at miss_label must always call a
2138defd9ff6930b4e24729971a61cf7469daf119beSteve Block// backup property store that is complete. This function is safe to
2148defd9ff6930b4e24729971a61cf7469daf119beSteve Block// call if name is not a symbol, and will jump to the miss_label in
2158defd9ff6930b4e24729971a61cf7469daf119beSteve Block// that case. The generated code assumes that the receiver has slow
2168defd9ff6930b4e24729971a61cf7469daf119beSteve Block// properties, is not a global object and does not have interceptors.
2178defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateDictionaryStore(MacroAssembler* masm,
2188defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Label* miss_label,
2198defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register elements,
2208defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register name,
2218defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register value,
2228defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register r0,
2238defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register r1) {
2248defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register use:
2258defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2268defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // elements - holds the property dictionary on entry and is clobbered.
2278defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2288defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // name - holds the name of the property on entry and is unchanged.
2298defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2308defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // value - holds the value to store and is unchanged.
2318defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2328defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r0 - used for index into the property dictionary and is clobbered.
2338defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2348defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r1 - used to hold the capacity of the property dictionary and is clobbered.
2358defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label done;
2368defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2378defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2388defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Probe the dictionary.
2398defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryProbes(masm,
2408defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 miss_label,
2418defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 &done,
2428defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 elements,
2438defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 name,
2448defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r0,
2458defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r1);
2468defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2478defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If probing finds an entry in the dictionary, r0 contains the
2488defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // index into the dictionary. Check that the value is a normal
2498defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // property that is not read only.
2508defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&done);
2518defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kElementsStartOffset =
2528defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kHeaderSize +
2538defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
2548defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
2558defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kTypeAndReadOnlyMask
2568defd9ff6930b4e24729971a61cf7469daf119beSteve Block      = (PropertyDetails::TypeField::mask() |
2578defd9ff6930b4e24729971a61cf7469daf119beSteve Block         PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
2588defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
2598defd9ff6930b4e24729971a61cf7469daf119beSteve Block          Immediate(kTypeAndReadOnlyMask));
2608defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_zero, miss_label, not_taken);
2618defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2628defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Store the value at the masked, scaled index.
2638defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kValueOffset = kElementsStartOffset + kPointerSize;
2648defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
2658defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(Operand(r0, 0), value);
2668defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2678defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Update write barrier. Make sure not to clobber the value.
2688defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r1, value);
2698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ RecordWrite(elements, r0, r1);
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2736ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void GenerateNumberDictionaryLoad(MacroAssembler* masm,
2746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Label* miss,
2756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register elements,
2766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register key,
2776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r0,
2786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r1,
2797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                         Register r2,
2807f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                         Register result) {
2816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Register use:
2826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // elements - holds the slow-case elements of the receiver and is unchanged.
2846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // key      - holds the smi key on entry and is unchanged.
2866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Scratch registers:
2886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r0 - holds the untagged key on entry and holds the hash once computed.
2906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r1 - used to hold the capacity mask of the dictionary
2926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r2 - used for the index into the dictionary.
2947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //
2957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // result - holds the result on exit if the load succeeds and we fall through.
2967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
2976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label done;
2986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Compute the hash code from the untagged key.  This must be kept in sync
3006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // with ComputeIntegerHash in utils.h.
3016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
3026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = ~hash + (hash << 15);
3036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ not_(r0);
3056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shl(r1, 15);
3066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(r0, Operand(r1));
3076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 12);
3086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 12);
3106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
3116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash + (hash << 2);
3126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ lea(r0, Operand(r0, r0, times_4, 0));
3136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 4);
3146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 4);
3166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
3176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash * 2057;
3186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ imul(r0, r0, 2057);
3196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 16);
3206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 16);
3226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
3236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Compute capacity mask.
3256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
3266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, kSmiTagSize);  // convert smi to int
3276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ dec(r1);
3286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Generate an unrolled loop that performs a few probes before giving up.
3306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kProbes = 4;
3316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  for (int i = 0; i < kProbes; i++) {
3326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Use r2 for index calculations and keep the hash intact in r0.
3336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ mov(r2, r0);
3346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Compute the masked index: (hash + i + i * i) & mask.
3356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (i > 0) {
3366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
3376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
3386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ and_(r2, Operand(r1));
3396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Scale the index by multiplying by the entry size.
3416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(NumberDictionary::kEntrySize == 3);
3426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ lea(r2, Operand(r2, r2, times_2, 0));  // r2 = r2 * 3
3436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Check if the key matches.
3456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ cmp(key, FieldOperand(elements,
3466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             r2,
3476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             times_pointer_size,
3486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             NumberDictionary::kElementsStartOffset));
3496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (i != (kProbes - 1)) {
3506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(equal, &done, taken);
3516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    } else {
3526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(not_equal, miss, not_taken);
3536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
3546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
3556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&done);
3576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the value is a normal propety.
3586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kDetailsOffset =
3596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
3606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT_EQ(NORMAL, 0);
3616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
3626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
3636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_zero, miss);
3646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the value at the masked, scaled index.
3666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kValueOffset =
3676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      NumberDictionary::kElementsStartOffset + kPointerSize;
3687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
3696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
3706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The offset from the inlined patch site to the start of the
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// inlined load instruction.  It is 7 bytes (test eax, imm) plus
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6 bytes (jne slow_label).
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst int LoadIC::kOffsetToLoadInstruction = 13;
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateArrayLength(MacroAssembler* masm) {
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
380402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateStringLength(MacroAssembler* masm) {
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
394402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
400402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
408402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Checks the receiver for special cases (value type, slow case bits).
4217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Falls through for regular JS object.
4227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
4237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           Register receiver,
4249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                           Register map,
4258defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           int interceptor_bit,
4267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           Label* slow) {
4277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
4287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   receiver - holds the receiver and is unchanged.
4297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Scratch registers:
4309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //   map - used to hold the map of the receiver.
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
4337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(receiver, Immediate(kSmiTagMask));
4347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, slow, not_taken);
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map of the receiver.
4379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
438d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
439d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check bit field.
4409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ test_b(FieldOperand(map, Map::kBitFieldOffset),
4418defd9ff6930b4e24729971a61cf7469daf119beSteve Block            (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
4427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(not_zero, slow, not_taken);
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object EXCEPT JS Value type.
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In the case that the object is a value-wrapper object,
445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we enter the runtime system to make sure that indexing
4467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // into string objects works as intended.
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
4487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ CmpInstanceType(map, JS_OBJECT_TYPE);
4507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(below, slow, not_taken);
4517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
4527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Loads an indexed element from a fast case array.
4557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateFastArrayLoad(MacroAssembler* masm,
4567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register receiver,
4577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register key,
4587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register scratch,
4597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register result,
4607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Label* not_fast_array,
4617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Label* out_of_range) {
4627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
4637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   receiver - holds the receiver and is unchanged.
4647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   key - holds the key and is unchanged (must be a smi).
4657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Scratch registers:
4667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   scratch - used to hold elements of the receiver and the loaded value.
4677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   result - holds the result on exit if the load succeeds and
4687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //            we fall through.
4697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is in fast mode (not dictionary).
4727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true);
473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key (index) is within bounds.
4747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
4757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(above_equal, out_of_range);
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the load.
4777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
4787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
4797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(Operand(scratch), Immediate(Factory::the_hole_value()));
480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In case the loaded value is the_hole we have to consult GetProperty
481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to ensure the prototype chain is searched.
4827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(equal, out_of_range);
4837f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (!result.is(scratch)) {
4847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ mov(result, scratch);
4857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
4867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
4877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Checks whether a key is an array index string or a symbol string.
4909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen// Falls through if the key is a symbol.
4917f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateKeyStringCheck(MacroAssembler* masm,
4927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Register key,
4937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Register map,
4947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Register hash,
4957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Label* index_string,
4967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Label* not_symbol) {
4977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
4987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   key - holds the key and is unchanged. Assumed to be non-smi.
4997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Scratch registers:
5007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   map - used to hold the map of the key.
5017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   hash - used to hold the hash of the key.
5027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
5037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(above_equal, not_symbol);
5047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Is the string an array index, with cached numeric value?
5067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
5077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
5087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, index_string, not_taken);
5097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Is the string a symbol?
5117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(kSymbolTag != 0);
5127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
5137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, not_symbol, not_taken);
5147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
5157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Picks out an array index from the hash field.
5187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateIndexFromHash(MacroAssembler* masm,
5197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register key,
5209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                  Register hash) {
5217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
5227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   key - holds the overwritten key on exit.
5237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   hash - holds the key's hash. Clobbered.
5247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // The assert checks that the constants for the maximum number of digits
5267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // for an array index cached in the hash field and the number of bits
5277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // reserved for it does not conflict.
5287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         (1 << String::kArrayIndexValueBits));
5307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // We want the smi-tagged index in key.  kArrayIndexValueMask has zeros in
5317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // the low kHashShift bits.
5327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(String::kHashShift >= kSmiTagSize);
5337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ and_(hash, String::kArrayIndexValueMask);
5347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ shr(hash, String::kHashShift - kSmiTagSize);
5357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Here we actually clobber the key which will be used if calling into
5367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // runtime later. However as the new key is the numeric value of a string key
5377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // there is no difference in using either key.
5387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(key, hash);
5397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
5407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
5437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
5447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- eax    : key
5457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- edx    : receiver
5467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0] : return address
5477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
548bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Label slow, check_string, index_smi, index_string, property_array_property;
5497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label check_pixel_array, probe_dictionary, check_number_dictionary;
5507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the key is a smi.
5527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(eax, Immediate(kSmiTagMask));
5537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(not_zero, &check_string, not_taken);
5547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_smi);
5557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Now the key is known to be a smi. This place is also jumped to from
5567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // where a numeric string is converted to a smi.
5577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5588defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
5598defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
5608defd9ff6930b4e24729971a61cf7469daf119beSteve Block
5617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateFastArrayLoad(masm,
5627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        edx,
5637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        eax,
5647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        ecx,
5657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        eax,
5667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        &check_pixel_array,
5677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        &slow);
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
569a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
570a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
572402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check whether the elements is a pixel array.
573402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
574402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
575402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx: elements
5767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, eax);
5777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ SmiUntag(ebx);
5786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true);
579402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
581402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
582402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
583402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiTag(eax);
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&check_number_dictionary);
5876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check whether the elements is a number dictionary.
5886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
5896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ebx: untagged index
5906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: key
5916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: elements
5926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
5936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label slow_pop_receiver;
5946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Push receiver on the stack to free up a register for the dictionary
5956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // probing.
5966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
5976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateNumberDictionaryLoad(masm,
5986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               &slow_pop_receiver,
5996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               ecx,
6006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               eax,
6016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               ebx,
6026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               edx,
6037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                               edi,
6047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                               eax);
6056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Pop receiver before returning.
6066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(edx);
6076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);
6086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
6096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&slow_pop_receiver);
6106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Pop the receiver from the stack and jump to runtime.
6116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(edx);
6126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
614402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Slow case: jump to runtime.
615402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
616402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
618402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_string);
6217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
622e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6238defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
6248defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
6258defd9ff6930b4e24729971a61cf7469daf119beSteve Block
626e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If the receiver is a fast-case object, check the keyed lookup
627402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // cache. Otherwise probe the dictionary.
628402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
629e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
630e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke         Immediate(Factory::hash_table_map()));
631e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &probe_dictionary);
632e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
633e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the map of the receiver, compute the keyed lookup cache hash
634e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // based on 32 bits of the map pointer and the string hash.
635402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
636402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, ebx);
637402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(ecx, KeyedLookupCache::kMapHashShift);
638402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
639402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(edi, String::kHashShift);
640402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ xor_(ecx, Operand(edi));
641402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(ecx, KeyedLookupCache::kCapacityMask);
642e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
643e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the key (consisting of map and symbol) from the cache and
644e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // check for match.
645e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_keys
646e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_keys();
647402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, ecx);
648e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ shl(edi, kPointerSizeLog2 + 1);
649e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
650e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
651e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ add(Operand(edi), Immediate(kPointerSize));
652402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
653e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
654e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
655bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  // Get field offset.
656402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx     : receiver
657402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx     : receiver's map
658402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax     : key
659402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx     : lookup cache index
660e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_field_offsets
661e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_field_offsets();
662402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi,
663402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
664402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
6657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ sub(edi, Operand(ecx));
666bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ j(above_equal, &property_array_property);
667e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
668e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load in-object property.
669402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
670402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ add(ecx, Operand(edi));
671402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
6727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
673e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(0);
674e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
675bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  // Load property array property.
676bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ bind(&property_array_property);
677bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
678bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
679bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch                           FixedArray::kHeaderSize));
680bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
681bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ ret(0);
682bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch
683e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Do a quick inline probe of the receiver's dictionary, if it
684e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // exists.
685e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&probe_dictionary);
6868defd9ff6930b4e24729971a61cf7469daf119beSteve Block
6878defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
6888defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
6898defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
6908defd9ff6930b4e24729971a61cf7469daf119beSteve Block
6918defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
694e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&index_string);
6969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateIndexFromHash(masm, eax, ebx);
6979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Now jump to the place where smi keys are handled.
6989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ jmp(&index_smi);
699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
702e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid KeyedLoadIC::GenerateString(MacroAssembler* masm) {
703e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
7046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : key (index)
705402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
706e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0] : return address
707e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
7086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
7096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label index_out_of_range;
7106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
7116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register receiver = edx;
7126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register index = eax;
7137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch1 = ebx;
7147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch2 = ecx;
7157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register result = eax;
7167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
7177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  StringCharAtGenerator char_at_generator(receiver,
7187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          index,
7197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          scratch1,
7207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          scratch2,
7217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          result,
7227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &miss,  // When not a string.
7237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &miss,  // When not a number.
7247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &index_out_of_range,
7257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          STRING_INDEX_IS_ARRAY_INDEX);
7267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_at_generator.GenerateFast(masm);
7277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ ret(0);
7287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
7297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ICRuntimeCallHelper call_helper;
7307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_at_generator.GenerateSlow(masm, call_helper);
731e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&index_out_of_range);
7336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Set(eax, Immediate(Factory::undefined_value()));
7346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);
735e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
736e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&miss);
737e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm);
738e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
739e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
740e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
7413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
7423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        ExternalArrayType array_type) {
7433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ----------- S t a t e -------------
744402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
745402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
7463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[0] : return address
7473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // -----------------------------------
7483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label slow, failed_allocation;
7493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object isn't a smi.
751402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
7523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &slow, not_taken);
7533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the key is a smi.
7553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(eax, Immediate(kSmiTagMask));
7563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow, not_taken);
7573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the map of the receiver.
759402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
7603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the receiver does not require access checks.  We need
7613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // to check this explicitly since this generic stub does not perform
7623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // map checks.
7637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
7647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            1 << Map::kIsAccessCheckNeeded);
7653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow, not_taken);
7663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
767402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
7683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow, not_taken);
7693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the elements array is the appropriate type of
7713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ExternalArray.
772402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
7733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
774402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
7753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(map));
7763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow, not_taken);
7773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
778402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key, known to be a smi.
779402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver, known to be a JSObject.
780402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: elements object, known to be an external array.
7813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the index is in range.
782402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, eax);
783402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiUntag(ecx);  // Untag the index.
784402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
7853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Unsigned comparison catches both negative and too-large values.
7863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(above_equal, &slow);
7873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
788402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
789402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: base pointer of external storage
7903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (array_type) {
7913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalByteArray:
792402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
7933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
7943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedByteArray:
795402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
7963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
7973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalShortArray:
798402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
7993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedShortArray:
801402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
8023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalIntArray:
8043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedIntArray:
805402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ mov(ecx, Operand(ebx, ecx, times_4, 0));
8063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalFloatArray:
808402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ fld_s(Operand(ebx, ecx, times_4, 0));
8093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    default:
8113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
8123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
8143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // For integer array types:
816402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx: value
8173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // For floating-point array type:
8183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // FP(0): value
8193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (array_type == kExternalIntArray ||
8213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      array_type == kExternalUnsignedIntArray) {
8223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // For the Int and UnsignedInt array types, we need to see whether
8233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // the value can be represented in a Smi. If not, we need to convert
8243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // it to a HeapNumber.
8253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label box_int;
8263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type == kExternalIntArray) {
827402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ cmp(ecx, 0xC0000000);
828402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ j(sign, &box_int);
8293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
8303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ASSERT_EQ(array_type, kExternalUnsignedIntArray);
8313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // The test is different for unsigned int values. Since we need
832402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // the value to be in the range of a positive smi, we can't
8333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // handle either of the top two bits being set in the value.
834402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ test(ecx, Immediate(0xC0000000));
8353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ j(not_zero, &box_int);
8363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
8373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
838402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
839402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiTag(eax);
8403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
8413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&box_int);
8433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Allocate a HeapNumber for the int and perform int-to-double
8453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // conversion.
8463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type == kExternalIntArray) {
847402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ push(ecx);
8483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_s(Operand(esp, 0));
849402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
8503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
8513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ASSERT(array_type == kExternalUnsignedIntArray);
8523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Need to zero-extend the value.
8533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // There's no fild variant for unsigned values, so zero-extend
8543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // to a 64-bit int manually.
8553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(Immediate(0));
856402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ push(ecx);
8573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_d(Operand(esp, 0));
858402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
859402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
8603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
8613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // FP(0): value
862402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
8633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Set the value.
864402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
8653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
8663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
8673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else if (array_type == kExternalFloatArray) {
8683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // For the floating-point array type, we need to always allocate a
8693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // HeapNumber.
870402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
8713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Set the value.
872402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
8733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
8743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
8753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
876402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
877402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiTag(eax);
8783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
8793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
8803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If we fail allocation of the HeapNumber, we still have a value on
8823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // top of the FPU stack. Remove it.
8833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&failed_allocation);
8843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ ffree();
8853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fincstp();
8863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Fall through to slow case.
8873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Slow case: Jump to runtime.
8893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&slow);
8903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
891402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
892402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
893402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
894402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
895402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
896402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
897402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
898402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
899402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0] : return address
900402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
901402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label slow;
902402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
903402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the receiver isn't a smi.
904402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
905402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(zero, &slow, not_taken);
906402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
907402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the key is a smi.
908402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(eax, Immediate(kSmiTagMask));
909402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
910402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
911402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the map of the receiver.
912402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
913402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
914402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that it has indexed interceptor and access checks
915402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // are not enabled for this object.
916402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
917402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
918402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
919402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
920402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
921402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Everything is fine, call runtime.
922402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ecx);
923402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
924402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // key
925402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);  // return address
926402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
927402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
9286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(
9296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      IC_Utility(kKeyedLoadPropertyWithInterceptor));
9306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
931402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
932402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&slow);
933402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
9343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
9353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
9406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
9416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow, fast, array, extra, check_pixel_array;
945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map from the receiver.
9506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver does not require access checks.  We need
952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to do this because this generic stub does not perform map checks.
9537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
9547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            1 << Map::kIsAccessCheckNeeded);
955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
9576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(ecx, Immediate(kSmiTagMask));
958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
9596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &array);
961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object.
9626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
9636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(below, &slow, not_taken);
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Object case: Check key against length in the elements array.
966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSObject
9686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key (a smi)
9696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is in fast mode (not dictionary).
9716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
9727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &fast, taken);
974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
977402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeSetProperty(masm);
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check whether the elements is a pixel array.
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
9816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: value
9827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ecx: key (a smi)
9836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
9846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
9856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the value is a smi. If a conversion is needed call into the
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // runtime to convert and clamp.
988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow);
9906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, ecx);
9916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ebx);
9926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
9946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ecx, eax);  // Save the value. Key is not longer needed.
9956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ecx);
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Clamp the value to [0..255].
9973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label done;
9986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ test(ecx, Immediate(0xFFFFFF00));
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(zero, &done);
10006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
10016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ dec_b(ecx);  // 0 if negative, 255 if positive.
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&done);
1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
10046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
10056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
10066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);  // Return value in eax.
1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Extra capacity case: Check if there is extra capacity to
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // perform the store and update the length. Used for adding one
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // element to the array by writing to array[array.length].
1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&extra);
1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
10136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSArray
10146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi.
10156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: receiver->elements, a FixedArray
10166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // flags: compare (ecx, edx.length())
1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
10187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow, not_taken);
10206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Add 1 to receiver->length, and go to fast array write.
10216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(FieldOperand(edx, JSArray::kLengthOffset),
10227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         Immediate(Smi::FromInt(1)));
1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&fast);
1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array case: Get the length and the elements array from the JS
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array. Check that the array is in fast mode; if it is the
1027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // length is always a smi.
1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&array);
1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
10306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSArray
10316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi.
10326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
10336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
1034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the key against the length in the array, compute the
1036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // address to store into and fall through to fast case.
10376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &extra, not_taken);
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the store.
1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&fast);
1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
10436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key (a smi)
10446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
10456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: FixedArray receiver->elements
104625f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update write barrier for the elements array address.
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(eax));
10496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ RecordWrite(edi, 0, edx, ecx);
1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
10553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                         ExternalArrayType array_type) {
10563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ----------- S t a t e -------------
10573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- eax    : value
10586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
10596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
10603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[0] : return address
10613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // -----------------------------------
10623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label slow, check_heap_number;
10633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object isn't a smi.
10653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(edx, Immediate(kSmiTagMask));
10663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &slow);
10673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the map from the receiver.
10686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
10693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the receiver does not require access checks.  We need
10703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // to do this because this generic stub does not perform map checks.
10717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
10727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            1 << Map::kIsAccessCheckNeeded);
10733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow);
10743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the key is a smi.
10756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(ecx, Immediate(kSmiTagMask));
10763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow);
10773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the instance type from the map of the receiver.
10786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, JS_OBJECT_TYPE);
10793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
10803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the elements array is the appropriate type of
10823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ExternalArray.
10833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // eax: value
10846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSObject
10856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi
10866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
10876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
10886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block              &slow, true);
10893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the index is in range.
10916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, ecx);
10926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ebx);
10936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
10943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Unsigned comparison catches both negative and too-large values.
10953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(above_equal, &slow);
10963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Handle both smis and HeapNumbers in the fast path. Go to the
10983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // runtime for all other kinds of values.
10993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // eax: value
11006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
11016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key
11026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
11033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: untagged index
11043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(eax, Immediate(kSmiTagMask));
11053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &check_heap_number);
11063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // smi case
11076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ecx, eax);  // Preserve the value in eax.  Key is no longer needed.
11086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ecx);
11096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
11103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ecx: base pointer of external storage
11113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (array_type) {
11123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalByteArray:
11133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedByteArray:
11146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
11153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
11163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalShortArray:
11173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedShortArray:
11186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
11193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
11203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalIntArray:
11213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedIntArray:
11226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(Operand(edi, ebx, times_4, 0), ecx);
11233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
11243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalFloatArray:
11253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Need to perform int-to-float conversion.
11266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ push(ecx);
11273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_s(Operand(esp, 0));
11286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ pop(ecx);
11296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ fstp_s(Operand(edi, ebx, times_4, 0));
11303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
11313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    default:
11323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
11333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
11343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
11356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);  // Return the original value.
11363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
11373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&check_heap_number);
11386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: value
11396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
11406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key
11416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
11426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ebx: untagged index
11433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
11443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(Factory::heap_number_map()));
11453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
11463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
11473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // The WebGL specification leaves the behavior of storing NaN and
11483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // +/-Infinity into integer arrays basically undefined. For more
11493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // reproducible behavior, convert these to zero.
11503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
11516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
11523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: untagged index
11536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: base pointer of external storage
11543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // top of FPU stack: value
11553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (array_type == kExternalFloatArray) {
11566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ fstp_s(Operand(edi, ebx, times_4, 0));
11573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
11583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
11593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Need to perform float-to-int conversion.
11603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Test the top of the FP stack for NaN.
11613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label is_nan;
11623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fucomi(0);
11633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ j(parity_even, &is_nan);
11643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
11653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type != kExternalUnsignedIntArray) {
11666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ push(ecx);  // Make room on stack
11673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fistp_s(Operand(esp, 0));
11686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ pop(ecx);
11693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
11703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // fistp stores values as signed integers.
11713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // To represent the entire range, we need to store as a 64-bit
11723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // int and discard the high 32 bits.
11736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ sub(Operand(esp), Immediate(2 * kPointerSize));
11743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fistp_d(Operand(esp, 0));
11756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ pop(ecx);
11766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(esp), Immediate(kPointerSize));
11773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
11786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // ecx: untagged integer value
11793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    switch (array_type) {
11803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalByteArray:
11813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedByteArray:
11826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
11833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
11843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalShortArray:
11853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedShortArray:
11866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
11873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
11883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalIntArray:
11893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedIntArray: {
11903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // We also need to explicitly check for +/-Infinity. These are
11913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // converted to MIN_INT, but we need to be careful not to
11923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // confuse with legal uses of MIN_INT.
11933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        Label not_infinity;
11943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // This test would apparently detect both NaN and Infinity,
11953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // but we've already checked for NaN using the FPU hardware
11963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // above.
11976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
11986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ and_(edx, 0x7FF0);
11996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ cmp(edx, 0x7FF0);
12003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ j(not_equal, &not_infinity);
12016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(ecx, 0);
12023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ bind(&not_infinity);
12036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(Operand(edi, ebx, times_4, 0), ecx);
12043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
12053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
12063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      default:
12073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        UNREACHABLE();
12083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
12093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
12106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ ret(0);  // Return original value.
12113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
12123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&is_nan);
12133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ffree();
12143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fincstp();
12153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    switch (array_type) {
12163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalByteArray:
12173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedByteArray:
12186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_b(Operand(edi, ebx, times_1, 0), 0);
12193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
12203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalShortArray:
12213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedShortArray:
12226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ xor_(ecx, Operand(ecx));
12236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
12243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
12253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalIntArray:
12263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedIntArray:
12276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
12283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
12293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      default:
12303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        UNREACHABLE();
12313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
12323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
12336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ ret(0);  // Return the original value.
12343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
12353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
12363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
12373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&slow);
1238402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeSetProperty(masm);
12393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
12403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
12413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallIC_Miss(Arguments args);
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// The generated code does not accept smi keys.
12467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// The generated code falls through if both probes miss.
12477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
12487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          int argc,
12499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                          Code::Kind kind) {
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1251e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
12527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- edx                 : receiver
1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
12549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  Label number, non_number, non_string, boolean, probe, miss;
1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags =
12587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch      Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the stub cache probing failed, the receiver might be a value.
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // For value objects, we use the map of the prototype objects for
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the corresponding JSValue for the cache and that is what we need
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to probe.
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for number.
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &number, not_taken);
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &non_number, taken);
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&number);
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::NUMBER_FUNCTION_INDEX, edx);
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for string.
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_number);
12787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &non_string, taken);
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::STRING_FUNCTION_INDEX, edx);
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for boolean.
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_string);
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::true_value());
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &boolean, not_taken);
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::false_value());
12899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ j(not_equal, &miss, taken);
1290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&boolean);
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache for the value object.
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&probe);
1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
12979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ bind(&miss);
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13018defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateFunctionTailCall(MacroAssembler* masm,
13028defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                     int argc,
13038defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                     Label* miss) {
1304e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
1305e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
13068defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- edi                 : function
1307e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1308e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1309e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1310e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1311e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1313e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the result is not a smi.
1314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ test(edi, Immediate(kSmiTagMask));
1315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
1316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the value is a JavaScript function, fetching its map into eax.
1318e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
1319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss, not_taken);
1320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen// The generated code falls through if the call should be handled by runtime.
13279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic void GenerateCallNormal(MacroAssembler* masm, int argc) {
1328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1329e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1330e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1331e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1332e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1333e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
13358defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label miss;
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13408defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
1341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13428defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // eax: elements
13438defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Search the dictionary placing the result in edi.
13448defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
13458defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateFunctionTailCall(masm, argc, &miss);
13469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
13479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ bind(&miss);
1348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
1352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1353e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1354e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1355e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1356e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1357e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13608defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (id == IC::kCallIC_Miss) {
13618defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ IncrementCounter(&Counters::call_miss, 1);
13628defd9ff6930b4e24729971a61cf7469daf119beSteve Block  } else {
13638defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ IncrementCounter(&Counters::keyed_call_miss, 1);
13648defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
13658defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter an internal frame.
1370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterInternalFrame();
1371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the receiver and the name of the function.
1373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(edx);
1374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(ecx);
1375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the entry.
1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CEntryStub stub(1);
1378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Immediate(2));
13797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, Immediate(ExternalReference(IC_Utility(id))));
1380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallStub(&stub);
1381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move result to edi and exit the internal frame.
1383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edi, eax);
1384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveInternalFrame();
1385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the receiver is a global object of some sort.
13878defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // This can happen only for regular CallIC but not KeyedCallIC.
13888defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (id == IC::kCallIC_Miss) {
13898defd9ff6930b4e24729971a61cf7469daf119beSteve Block    Label invoke, global;
13908defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
13918defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ test(edx, Immediate(kSmiTagMask));
13928defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ j(zero, &invoke, not_taken);
13938defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
13948defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
13958defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
13968defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ j(equal, &global);
13978defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
13988defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ j(not_equal, &invoke);
13998defd9ff6930b4e24729971a61cf7469daf119beSteve Block
14008defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Patch the receiver on the stack.
14018defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ bind(&global);
14028defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
14038defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
14048defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ bind(&invoke);
14058defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
1406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
14147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
14157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ecx                 : name
14167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0]              : return address
14177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
14187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ...
14197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
14207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
14217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Get the receiver of the function from the stack; 1 ~ return address.
14237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
14249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
14257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
14267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
14277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
14309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
14319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
14329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
14339dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
14349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
14359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
14369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
14379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
14389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateCallNormal(masm, argc);
14397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
14407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
14417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
14449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
14459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
14469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
14479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
14489dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
14499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
14509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
14519dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
14527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
14537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
14547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
14577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
14587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ecx                 : name
14597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0]              : return address
14607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
14617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ...
14627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
14637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
14647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Get the receiver of the function from the stack; 1 ~ return address.
14667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
14677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label do_call, slow_call, slow_load, slow_reload_receiver;
14697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
14707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label index_smi, index_string;
14717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the key is a smi.
14737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(ecx, Immediate(kSmiTagMask));
14747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(not_zero, &check_string, not_taken);
14757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_smi);
14777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Now the key is known to be a smi. This place is also jumped to from
14787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // where a numeric string is converted to a smi.
14797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14808defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
14818defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
14827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateFastArrayLoad(
14849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
14857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1);
14867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&do_call);
14887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // receiver in edx is not used after this point.
14897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ecx: key
14907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // edi: function
14918defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateFunctionTailCall(masm, argc, &slow_call);
14927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
14937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&check_number_dictionary);
14947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // eax: elements
14957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ecx: smi key
14967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check whether the elements is a number dictionary.
14977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true);
14987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, ecx);
14997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ SmiUntag(ebx);
15007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ebx: untagged index
15017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Receiver in edx will be clobbered, need to reload it on miss.
15029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateNumberDictionaryLoad(
15039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
15047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1);
15057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ jmp(&do_call);
15067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&slow_reload_receiver);
15087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
15097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&slow_load);
15117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // This branch is taken when calling KeyedCallIC_Miss is neither required
15127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // nor beneficial.
15137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1);
15147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ EnterInternalFrame();
15157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ push(ecx);  // save the key
15167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ push(edx);  // pass the receiver
15177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ push(ecx);  // pass the key
15187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
15197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ pop(ecx);  // restore the key
15207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ LeaveInternalFrame();
15217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edi, eax);
15227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ jmp(&do_call);
15237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&check_string);
15257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
15267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // The key is known to be a symbol.
15287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // If the receiver is a regular JS object with slow properties then do
15297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // a quick inline probe of the receiver's dictionary.
15307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Otherwise do the monomorphic cache probe.
15318defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
15328defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
15337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
15358defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
15367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15378defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
15387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
15397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ jmp(&do_call);
15407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&lookup_monomorphic_cache);
15427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1);
15439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
15447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Fall through on miss.
15457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&slow_call);
15477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // This branch is taken if:
15487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - the receiver requires boxing or access check,
15497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - the key is neither smi nor symbol,
15507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - the value loaded is not a function,
15517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - there is hope that the runtime will create a monomorphic call stub
15527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   that will get fetched next time.
15537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_slow, 1);
15547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
15557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_string);
15579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateIndexFromHash(masm, ecx, ebx);
15589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Now jump to the place where smi keys are handled.
15599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ jmp(&index_smi);
15607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
15617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
15649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
15659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
15669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
15679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
15689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
15699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
15709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
15719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
15729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateCallNormal(masm, argc);
15737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
15747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
15757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
15789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
15799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
15809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
15819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
15829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
15839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
15849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
15859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
15867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
15877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
15887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
15897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadIC_Miss(Arguments args);
1592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1593a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1594a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1595402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1596a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1597a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
1601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1607402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateNormal(MacroAssembler* masm) {
1612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1613402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
16178defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label miss;
1618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16198defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
1620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16218defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // edx: elements
1622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Search the dictionary placing the result in eax.
16238defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
1624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Cache miss: Jump to runtime.
1627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1628402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMiss(MacroAssembler* masm) {
1633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1634402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16398defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::load_miss, 1);
16408defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // receiver
1643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);  // name
1644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
16476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
16486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
1649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// One byte opcode for test eax,0xXXXXXXXX.
1653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const byte kTestEaxByte = 0xA9;
1654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The address of the instruction following the call.
1657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the instruction following the call is not a test eax, nothing
1660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // was inlined.
1661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (*test_instruction_address != kTestEaxByte) return false;
1662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The delta to the start of the map check instruction.
1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The map address is the last 4 bytes of the 7-byte
1668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand-immediate compare instruction, so we add 3 to get the
1669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The offset is in the last 4 bytes of a six byte
1674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // memory-to-register move instruction, so we add 2 to get the
1675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address offset_address =
1677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
168350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsenbool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
168450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // The address of the instruction following the call.
168550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address test_instruction_address =
168650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen      address + Assembler::kCallTargetAddressOffset;
168750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
168850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // If the instruction following the call is not a test eax, nothing
168950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // was inlined.
169050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  if (*test_instruction_address != kTestEaxByte) return false;
169150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
169250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Extract the encoded deltas from the test eax instruction.
169350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address encoded_offsets_address = test_instruction_address + 1;
169450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
169550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  int delta_to_map_check = -(encoded_offsets & 0xFFFF);
169650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  int delta_to_record_write = encoded_offsets >> 16;
169750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
169850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Patch the map to check. The map address is the last 4 bytes of
169950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // the 7-byte operand-immediate compare instruction.
170050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address map_check_address = test_instruction_address + delta_to_map_check;
170150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address map_address = map_check_address + 3;
170250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  *(reinterpret_cast<Object**>(map_address)) = map;
170350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
170450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Patch the offset in the store instruction. The offset is in the
170550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // last 4 bytes of a six byte register-to-memory move instruction.
170650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address offset_address =
170750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen      map_check_address + StoreIC::kOffsetToStoreInstruction + 2;
170850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // The offset should have initial value (kMaxInt - 1), cleared value
170950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // (-1) or we should be clearing the inlined version.
171050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
171150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         *reinterpret_cast<int*>(offset_address) == -1 ||
171250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         (offset == 0 && map == Heap::null_value()));
171350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
171450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
171550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Patch the offset in the write-barrier code. The offset is the
171650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // last 4 bytes of a six byte lea instruction.
171750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  offset_address = map_check_address + delta_to_record_write + 2;
171850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // The offset should have initial value (kMaxInt), cleared value
171950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // (-1) or we should be clearing the inlined version.
172050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
172150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         *reinterpret_cast<int*>(offset_address) == -1 ||
172250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         (offset == 0 && map == Heap::null_value()));
172350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
172450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
172550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  return true;
172650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen}
172750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
172850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
1729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool PatchInlinedMapCheck(Address address, Object* map) {
1730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The keyed load has a fast inlined case if the IC call instruction
1733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is immediately followed by a test instruction.
1734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (*test_instruction_address != kTestEaxByte) return false;
1735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch the offset from the test instruction to the map cmp
1737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction.  This offset is stored in the last 4 bytes of the 5
1738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // byte test instruction.
1739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the map address.  The map address is in the last 4 bytes
1742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the 7-byte operand-immediate compare instruction, so we add 3
1743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the offset to get the map address.
1744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the map check.
1746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadIC_Miss(Arguments args);
1763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1767402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1768402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
17728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::keyed_load_miss, 1);
17738defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1774402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ebx);
1775402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1776402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // name
1777402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ebx);  // return address
1778402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1779402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
17806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
17816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
1782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1785402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1787402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1788402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1793402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // name
1795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
17986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
18064515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
18164515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  GenerateMiss(masm);
1817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid StoreIC::GenerateMiss(MacroAssembler* masm) {
1821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
18244515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
18294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(edx);
1830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
1831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);
1832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);
1833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
18356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
18366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 3, 1);
18376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
18386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
184050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen// The offset from the inlined patch site to the start of the inlined
184150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen// store instruction.  It is 7 bytes (test reg, imm) plus 6 bytes (jne
184250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen// slow_label).
184350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsenconst int StoreIC::kOffsetToStoreInstruction = 13;
184450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
184550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
18466ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockvoid StoreIC::GenerateArrayLength(MacroAssembler* masm) {
18476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
18486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : value
18496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : name
18506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
18516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[0] : return address
18526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
18536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
18546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // This accepts as a receiver anything JSObject::SetElementsLength accepts
18556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // (currently anything except for external and pixel arrays which means
18566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // anything with elements of FixedArray type.), but currently is restricted
18576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // to JSArray.
18586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Value must be a number, but only smis are accepted as the most common case.
18596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
18616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register receiver = edx;
18636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register value = eax;
18646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register scratch = ebx;
18656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the receiver isn't a smi.
18676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(receiver, Immediate(kSmiTagMask));
18686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(zero, &miss, not_taken);
18696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the object is a JS array.
18716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
18726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &miss, not_taken);
18736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that elements are FixedArray.
18756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
18766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
18776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &miss, not_taken);
18786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that value is a smi.
18806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(value, Immediate(kSmiTagMask));
18816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_zero, &miss, not_taken);
18826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Prepare tail call to StoreIC_ArrayLength.
18846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(scratch);
18856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(receiver);
18866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(value);
18876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(scratch);  // return address
18886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
18906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
18916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
18936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
18946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateMiss(masm);
1895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
18988defd9ff6930b4e24729971a61cf7469daf119beSteve Blockvoid StoreIC::GenerateNormal(MacroAssembler* masm) {
18998defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // ----------- S t a t e -------------
19008defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- eax    : value
19018defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- ecx    : name
19028defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- edx    : receiver
19038defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- esp[0] : return address
19048defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // -----------------------------------
19058defd9ff6930b4e24729971a61cf7469daf119beSteve Block
19068defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label miss, restore_miss;
19078defd9ff6930b4e24729971a61cf7469daf119beSteve Block
19088defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
19098defd9ff6930b4e24729971a61cf7469daf119beSteve Block
19108defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // A lot of registers are needed for storing to slow case
19118defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // objects. Push and restore receiver but rely on
19128defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // GenerateDictionaryStore preserving the value and name.
19138defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ push(edx);
19148defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
19158defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ Drop(1);
19168defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::store_normal_hit, 1);
19178defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ ret(0);
19188defd9ff6930b4e24729971a61cf7469daf119beSteve Block
19198defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&restore_miss);
19208defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ pop(edx);
19218defd9ff6930b4e24729971a61cf7469daf119beSteve Block
19228defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&miss);
19238defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::store_normal_miss, 1);
19248defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateMiss(masm);
19258defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
19268defd9ff6930b4e24729971a61cf7469daf119beSteve Block
19278defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedStoreIC_Miss(Arguments args);
1930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1931402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
19346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
19356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
1936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(ebx);
19406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
1941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
19426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(eax);
19436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(ebx);
1944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
19466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
1947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1950402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
19536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
19546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
1955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(ebx);
19596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
1960402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);
19616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(eax);
19626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(ebx);
1963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
19656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
19666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 3, 1);
1967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
1970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
1973f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
1974f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_IA32
1975