ic-ia32.cc revision e0cee9b3ed82e2391fd85d118aeaa4ea361c687d
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"
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ----------------------------------------------------------------------------
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Static IC stub generators.
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
478defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
488defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                            Register type,
498defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                            Label* global_object) {
508defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register usage:
518defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   type: holds the receiver instance type on entry.
528defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
538defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(equal, global_object, not_taken);
548defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
558defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(equal, global_object, not_taken);
568defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(type, JS_GLOBAL_PROXY_TYPE);
578defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(equal, global_object, not_taken);
588defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
618defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Generated code falls through if the receiver is a regular non-global
628defd9ff6930b4e24729971a61cf7469daf119beSteve Block// JS object with slow properties and no interceptors.
638defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
648defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Register receiver,
658defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Register r0,
668defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Register r1,
678defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                                  Label* miss) {
688defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register usage:
698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   receiver: holds the receiver on entry and is unchanged.
708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   r0: used to hold receiver instance type.
718defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //       Holds the property dictionary on fall through.
728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //   r1: used to hold receivers map.
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check that the receiver isn't a smi.
758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test(receiver, Immediate(kSmiTagMask));
768defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(zero, miss, not_taken);
778defd9ff6930b4e24729971a61cf7469daf119beSteve Block
788defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check that the receiver is a valid JS object.
798defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
808defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
818defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ cmp(r0, FIRST_JS_OBJECT_TYPE);
828defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(below, miss, not_taken);
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
848defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If this assert fails, we have to check upper bound too.
858defd9ff6930b4e24729971a61cf7469daf119beSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
878defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateGlobalInstanceTypeCheck(masm, r0, miss);
888defd9ff6930b4e24729971a61cf7469daf119beSteve Block
898defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Check for non-global object that requires access check.
908defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
918defd9ff6930b4e24729971a61cf7469daf119beSteve Block            (1 << Map::kIsAccessCheckNeeded) |
928defd9ff6930b4e24729971a61cf7469daf119beSteve Block            (1 << Map::kHasNamedInterceptor));
938defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_zero, miss, not_taken);
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
95402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
968defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ CheckMap(r0, Factory::hash_table_map(), miss, true);
978defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
98e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1008defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Probe the string dictionary in the |elements| register. Jump to the
1018defd9ff6930b4e24729971a61cf7469daf119beSteve Block// |done| label if a property with the given name is found leaving the
1028defd9ff6930b4e24729971a61cf7469daf119beSteve Block// index into the dictionary in |r0|. Jump to the |miss| label
1038defd9ff6930b4e24729971a61cf7469daf119beSteve Block// otherwise.
1048defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateStringDictionaryProbes(MacroAssembler* masm,
1058defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Label* miss,
1068defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Label* done,
1078defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register elements,
1088defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register name,
1098defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register r0,
1108defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           Register r1) {
111e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Assert that name contains a string.
112e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  if (FLAG_debug_code) __ AbortIfNotString(name);
113e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the capacity mask.
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kCapacityOffset =
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kCapacityIndex * kPointerSize;
1188defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r1, FieldOperand(elements, kCapacityOffset));
1198defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ shr(r1, kSmiTagSize);  // convert smi to int
1208defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ dec(r1);
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate an unrolled loop that performs a few probes before
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // giving up. Measurements done on Gmail indicate that 2 probes
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // cover ~93% of loads from dictionaries.
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kProbes = 4;
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kElementsStartOffset =
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kProbes; i++) {
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the masked index: (hash + i + i * i) & mask.
1318defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(r0, FieldOperand(name, String::kHashFieldOffset));
1328defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ shr(r0, String::kHashShift);
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i > 0) {
1348defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ add(Operand(r0), Immediate(StringDictionary::GetProbeOffset(i)));
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
1368defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ and_(r0, Operand(r1));
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Scale the index by multiplying by the entry size.
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(StringDictionary::kEntrySize == 3);
1408defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ lea(r0, Operand(r0, r0, times_2, 0));  // r0 = r0 * 3
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if the key is identical to the name.
1438defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(name, Operand(elements, r0, times_4,
1448defd9ff6930b4e24729971a61cf7469daf119beSteve Block                         kElementsStartOffset - kHeapObjectTag));
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i != kProbes - 1) {
1468defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(equal, done, taken);
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
1488defd9ff6930b4e24729971a61cf7469daf119beSteve Block      __ j(not_equal, miss, not_taken);
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1518defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
1528defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1538defd9ff6930b4e24729971a61cf7469daf119beSteve Block
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1558defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Helper function used to load a property from a dictionary backing
1568defd9ff6930b4e24729971a61cf7469daf119beSteve Block// storage. This function may fail to load a property even though it is
1578defd9ff6930b4e24729971a61cf7469daf119beSteve Block// in the dictionary, so code at miss_label must always call a backup
1588defd9ff6930b4e24729971a61cf7469daf119beSteve Block// property load that is complete. This function is safe to call if
1598defd9ff6930b4e24729971a61cf7469daf119beSteve Block// name is not a symbol, and will jump to the miss_label in that
1608defd9ff6930b4e24729971a61cf7469daf119beSteve Block// case. The generated code assumes that the receiver has slow
1618defd9ff6930b4e24729971a61cf7469daf119beSteve Block// properties, is not a global object and does not have interceptors.
1628defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateDictionaryLoad(MacroAssembler* masm,
1638defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Label* miss_label,
1648defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register elements,
1658defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register name,
1668defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register r0,
1678defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register r1,
1688defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                   Register result) {
1698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register use:
1708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1718defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // elements - holds the property dictionary on entry and is unchanged.
1728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1738defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // name - holds the name of the property on entry and is unchanged.
1748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Scratch registers:
1768defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1778defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r0   - used for the index into the property dictionary
1788defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1798defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r1   - used to hold the capacity of the property dictionary.
1808defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
1818defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // result - holds the result on exit.
1828defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1838defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label done;
1848defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1858defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Probe the dictionary.
1868defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryProbes(masm,
1878defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 miss_label,
1888defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 &done,
1898defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 elements,
1908defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 name,
1918defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r0,
1928defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r1);
1938defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1948defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If probing finds an entry in the dictionary, r0 contains the
1958defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // index into the dictionary. Check that the value is a normal
1968defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // property.
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
1988defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kElementsStartOffset =
1998defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kHeaderSize +
2008defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
2028defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, miss_label, not_taken);
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the value at the masked, scaled index.
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kValueOffset = kElementsStartOffset + kPointerSize;
2088defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
2098defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
2108defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2118defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2128defd9ff6930b4e24729971a61cf7469daf119beSteve Block// Helper function used to store a property to a dictionary backing
2138defd9ff6930b4e24729971a61cf7469daf119beSteve Block// storage. This function may fail to store a property eventhough it
2148defd9ff6930b4e24729971a61cf7469daf119beSteve Block// is in the dictionary, so code at miss_label must always call a
2158defd9ff6930b4e24729971a61cf7469daf119beSteve Block// backup property store that is complete. This function is safe to
2168defd9ff6930b4e24729971a61cf7469daf119beSteve Block// call if name is not a symbol, and will jump to the miss_label in
2178defd9ff6930b4e24729971a61cf7469daf119beSteve Block// that case. The generated code assumes that the receiver has slow
2188defd9ff6930b4e24729971a61cf7469daf119beSteve Block// properties, is not a global object and does not have interceptors.
2198defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateDictionaryStore(MacroAssembler* masm,
2208defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Label* miss_label,
2218defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register elements,
2228defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register name,
2238defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register value,
2248defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register r0,
2258defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                    Register r1) {
2268defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Register use:
2278defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2288defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // elements - holds the property dictionary on entry and is clobbered.
2298defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2308defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // name - holds the name of the property on entry and is unchanged.
2318defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2328defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // value - holds the value to store and is unchanged.
2338defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2348defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r0 - used for index into the property dictionary and is clobbered.
2358defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //
2368defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // r1 - used to hold the capacity of the property dictionary and is clobbered.
2378defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label done;
2388defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2398defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2408defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Probe the dictionary.
2418defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryProbes(masm,
2428defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 miss_label,
2438defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 &done,
2448defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 elements,
2458defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 name,
2468defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r0,
2478defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                 r1);
2488defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2498defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // If probing finds an entry in the dictionary, r0 contains the
2508defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // index into the dictionary. Check that the value is a normal
2518defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // property that is not read only.
2528defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&done);
2538defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kElementsStartOffset =
2548defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kHeaderSize +
2558defd9ff6930b4e24729971a61cf7469daf119beSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
2568defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
2578defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kTypeAndReadOnlyMask
2588defd9ff6930b4e24729971a61cf7469daf119beSteve Block      = (PropertyDetails::TypeField::mask() |
2598defd9ff6930b4e24729971a61cf7469daf119beSteve Block         PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
2608defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
2618defd9ff6930b4e24729971a61cf7469daf119beSteve Block          Immediate(kTypeAndReadOnlyMask));
2628defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ j(not_zero, miss_label, not_taken);
2638defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2648defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Store the value at the masked, scaled index.
2658defd9ff6930b4e24729971a61cf7469daf119beSteve Block  const int kValueOffset = kElementsStartOffset + kPointerSize;
2668defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
2678defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(Operand(r0, 0), value);
2688defd9ff6930b4e24729971a61cf7469daf119beSteve Block
2698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Update write barrier. Make sure not to clobber the value.
2708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(r1, value);
2718defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ RecordWrite(elements, r0, r1);
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2756ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void GenerateNumberDictionaryLoad(MacroAssembler* masm,
2766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Label* miss,
2776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register elements,
2786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register key,
2796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r0,
2806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r1,
2817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                         Register r2,
2827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                         Register result) {
2836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Register use:
2846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // elements - holds the slow-case elements of the receiver and is unchanged.
2866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // key      - holds the smi key on entry and is unchanged.
2886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Scratch registers:
2906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r0 - holds the untagged key on entry and holds the hash once computed.
2926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r1 - used to hold the capacity mask of the dictionary
2946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
2956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r2 - used for the index into the dictionary.
2967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //
2977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // result - holds the result on exit if the load succeeds and we fall through.
2987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
2996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label done;
3006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Compute the hash code from the untagged key.  This must be kept in sync
3026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // with ComputeIntegerHash in utils.h.
3036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
3046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = ~hash + (hash << 15);
3056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ not_(r0);
3076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shl(r1, 15);
3086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(r0, Operand(r1));
3096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 12);
3106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 12);
3126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
3136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash + (hash << 2);
3146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ lea(r0, Operand(r0, r0, times_4, 0));
3156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 4);
3166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 4);
3186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
3196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash * 2057;
3206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ imul(r0, r0, 2057);
3216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 16);
3226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
3236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 16);
3246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
3256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Compute capacity mask.
3276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
3286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, kSmiTagSize);  // convert smi to int
3296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ dec(r1);
3306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Generate an unrolled loop that performs a few probes before giving up.
3326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kProbes = 4;
3336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  for (int i = 0; i < kProbes; i++) {
3346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Use r2 for index calculations and keep the hash intact in r0.
3356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ mov(r2, r0);
3366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Compute the masked index: (hash + i + i * i) & mask.
3376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (i > 0) {
3386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
3396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
3406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ and_(r2, Operand(r1));
3416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Scale the index by multiplying by the entry size.
3436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(NumberDictionary::kEntrySize == 3);
3446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ lea(r2, Operand(r2, r2, times_2, 0));  // r2 = r2 * 3
3456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Check if the key matches.
3476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ cmp(key, FieldOperand(elements,
3486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             r2,
3496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             times_pointer_size,
3506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             NumberDictionary::kElementsStartOffset));
3516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (i != (kProbes - 1)) {
3526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(equal, &done, taken);
3536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    } else {
3546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(not_equal, miss, not_taken);
3556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
3566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
3576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&done);
3596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the value is a normal propety.
3606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kDetailsOffset =
3616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
3626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT_EQ(NORMAL, 0);
3636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
3646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
3656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_zero, miss);
3666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the value at the masked, scaled index.
3686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kValueOffset =
3696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      NumberDictionary::kElementsStartOffset + kPointerSize;
3707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(result, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
3716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
3726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The offset from the inlined patch site to the start of the
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// inlined load instruction.  It is 7 bytes (test eax, imm) plus
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6 bytes (jne slow_label).
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst int LoadIC::kOffsetToLoadInstruction = 13;
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateArrayLength(MacroAssembler* masm) {
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
382402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid LoadIC::GenerateStringLength(MacroAssembler* masm,
3951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                  bool support_wrappers) {
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
397402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss,
4041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         support_wrappers);
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Checks the receiver for special cases (value type, slow case bits).
4257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Falls through for regular JS object.
4267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
4277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           Register receiver,
4289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                           Register map,
4298defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                           int interceptor_bit,
4307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                           Label* slow) {
4317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
4327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   receiver - holds the receiver and is unchanged.
4337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Scratch registers:
4349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //   map - used to hold the map of the receiver.
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
4377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(receiver, Immediate(kSmiTagMask));
4387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, slow, not_taken);
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map of the receiver.
4419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
442d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
443d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check bit field.
4449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ test_b(FieldOperand(map, Map::kBitFieldOffset),
4458defd9ff6930b4e24729971a61cf7469daf119beSteve Block            (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
4467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(not_zero, slow, not_taken);
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object EXCEPT JS Value type.
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In the case that the object is a value-wrapper object,
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we enter the runtime system to make sure that indexing
4507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // into string objects works as intended.
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
4527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4539dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ CmpInstanceType(map, JS_OBJECT_TYPE);
4547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(below, slow, not_taken);
4557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
4567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Loads an indexed element from a fast case array.
459756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick// If not_fast_array is NULL, doesn't perform the elements map check.
4607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateFastArrayLoad(MacroAssembler* masm,
4617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register receiver,
4627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register key,
4637f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register scratch,
4647f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Register result,
4657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Label* not_fast_array,
4667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                  Label* out_of_range) {
4677f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
4687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   receiver - holds the receiver and is unchanged.
4697f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   key - holds the key and is unchanged (must be a smi).
4707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Scratch registers:
4717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   scratch - used to hold elements of the receiver and the loaded value.
4727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   result - holds the result on exit if the load succeeds and
4737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //            we fall through.
4747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
476756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  if (not_fast_array != NULL) {
477756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    // Check that the object is in fast mode and writable.
478756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    __ CheckMap(scratch, Factory::fixed_array_map(), not_fast_array, true);
479756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  } else {
480756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    __ AssertFastElements(scratch);
481756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key (index) is within bounds.
4837f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
4847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(above_equal, out_of_range);
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the load.
4867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
4877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
4887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(Operand(scratch), Immediate(Factory::the_hole_value()));
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In case the loaded value is the_hole we have to consult GetProperty
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to ensure the prototype chain is searched.
4917f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(equal, out_of_range);
4927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  if (!result.is(scratch)) {
4937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch    __ mov(result, scratch);
4947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  }
4957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
4967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
4987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// Checks whether a key is an array index string or a symbol string.
4999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen// Falls through if the key is a symbol.
5007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateKeyStringCheck(MacroAssembler* masm,
5017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Register key,
5027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Register map,
5037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Register hash,
5047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Label* index_string,
5057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                   Label* not_symbol) {
5067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Register use:
5077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   key - holds the key and is unchanged. Assumed to be non-smi.
5087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Scratch registers:
5097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   map - used to hold the map of the key.
5107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   hash - used to hold the hash of the key.
5117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
5127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(above_equal, not_symbol);
5137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Is the string an array index, with cached numeric value?
5157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
5167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
5177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, index_string, not_taken);
5187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Is the string a symbol?
5207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  ASSERT(kSymbolTag != 0);
5217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
5227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(zero, not_symbol, not_taken);
5237f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
5247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
5277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
5287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- eax    : key
5297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- edx    : receiver
5307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0] : return address
5317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
532bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  Label slow, check_string, index_smi, index_string, property_array_property;
5337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label check_pixel_array, probe_dictionary, check_number_dictionary;
5347f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the key is a smi.
5367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(eax, Immediate(kSmiTagMask));
5377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(not_zero, &check_string, not_taken);
5387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_smi);
5397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Now the key is known to be a smi. This place is also jumped to from
5407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // where a numeric string is converted to a smi.
5417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
5428defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
5438defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
5448defd9ff6930b4e24729971a61cf7469daf119beSteve Block
545756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Check the "has fast elements" bit in the receiver's map which is
546756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // now in ecx.
547756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ test_b(FieldOperand(ecx, Map::kBitField2Offset),
548756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick            1 << Map::kHasFastElements);
549756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  __ j(zero, &check_pixel_array, not_taken);
550756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
5517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateFastArrayLoad(masm,
5527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        edx,
5537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        eax,
5547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        ecx,
5557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        eax,
556756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick                        NULL,
5577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                        &slow);
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
5621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block  GenerateFastPixelArrayLoad(masm,
5631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             edx,
5641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             eax,
5651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             ecx,
5661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             ebx,
5671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             eax,
5681e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             &check_number_dictionary,
5691e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             NULL,
5701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             &slow);
571a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&check_number_dictionary);
5736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check whether the elements is a number dictionary.
5746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
5756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ebx: untagged index
5766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: key
5776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: elements
5786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
5796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label slow_pop_receiver;
5806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Push receiver on the stack to free up a register for the dictionary
5816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // probing.
5826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
5836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateNumberDictionaryLoad(masm,
5846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               &slow_pop_receiver,
5856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               ecx,
5866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               eax,
5876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               ebx,
5886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               edx,
5897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                               edi,
5907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                               eax);
5916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Pop receiver before returning.
5926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(edx);
5936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);
5946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&slow_pop_receiver);
5966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Pop the receiver from the stack and jump to runtime.
5976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(edx);
5986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
600402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Slow case: jump to runtime.
601402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
602402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
604402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_string);
6077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
608e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
6098defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
6108defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
6118defd9ff6930b4e24729971a61cf7469daf119beSteve Block
612e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If the receiver is a fast-case object, check the keyed lookup
613402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // cache. Otherwise probe the dictionary.
614402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
615e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
616e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke         Immediate(Factory::hash_table_map()));
617e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &probe_dictionary);
618e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
619e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the map of the receiver, compute the keyed lookup cache hash
620e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // based on 32 bits of the map pointer and the string hash.
621402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
622402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, ebx);
623402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(ecx, KeyedLookupCache::kMapHashShift);
624402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
625402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(edi, String::kHashShift);
626402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ xor_(ecx, Operand(edi));
627402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(ecx, KeyedLookupCache::kCapacityMask);
628e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
629e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the key (consisting of map and symbol) from the cache and
630e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // check for match.
631e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_keys
632e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_keys();
633402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, ecx);
634e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ shl(edi, kPointerSizeLog2 + 1);
635e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
636e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
637e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ add(Operand(edi), Immediate(kPointerSize));
638402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
639e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
640e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
641bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  // Get field offset.
642402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx     : receiver
643402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx     : receiver's map
644402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax     : key
645402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx     : lookup cache index
646e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_field_offsets
647e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_field_offsets();
648402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi,
649402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
650402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
6517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ sub(edi, Operand(ecx));
652bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ j(above_equal, &property_array_property);
653e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
654e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load in-object property.
655402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
656402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ add(ecx, Operand(edi));
657402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
6587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
659e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(0);
660e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
661bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  // Load property array property.
662bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ bind(&property_array_property);
663bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
664bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
665bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch                           FixedArray::kHeaderSize));
666bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1);
667bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch  __ ret(0);
668bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch
669e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Do a quick inline probe of the receiver's dictionary, if it
670e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // exists.
671e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&probe_dictionary);
6728defd9ff6930b4e24729971a61cf7469daf119beSteve Block
6738defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
6748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
6758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
6768defd9ff6930b4e24729971a61cf7469daf119beSteve Block
6778defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
680e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&index_string);
68280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IndexFromHash(ebx, eax);
6839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Now jump to the place where smi keys are handled.
6849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ jmp(&index_smi);
685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
688e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid KeyedLoadIC::GenerateString(MacroAssembler* masm) {
689e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
6906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : key (index)
691402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
692e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0] : return address
693e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
6946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
6956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
6966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register receiver = edx;
6976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register index = eax;
6987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch1 = ebx;
6997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register scratch2 = ecx;
7007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Register result = eax;
7017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
7027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  StringCharAtGenerator char_at_generator(receiver,
7037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          index,
7047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          scratch1,
7057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          scratch2,
7067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          result,
7077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &miss,  // When not a string.
7087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          &miss,  // When not a number.
7090d5e116f6aee03185f237311a943491bb079a768Kristian Monsen                                          &miss,  // When index out of range.
7107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          STRING_INDEX_IS_ARRAY_INDEX);
7117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_at_generator.GenerateFast(masm);
7127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ ret(0);
7137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  StubRuntimeCallHelper call_helper;
7157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  char_at_generator.GenerateSlow(masm, call_helper);
716e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
717e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&miss);
718e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm);
719e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
720e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
721e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
722402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
723402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
724402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
725402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
726402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0] : return address
727402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
728402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label slow;
729402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
730402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the receiver isn't a smi.
731402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
732402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(zero, &slow, not_taken);
733402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
734f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // Check that the key is an array index, that is Uint32.
735f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  __ test(eax, Immediate(kSmiTagMask | kSmiSignMask));
736402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
737402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
738402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the map of the receiver.
739402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
740402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
741402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that it has indexed interceptor and access checks
742402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // are not enabled for this object.
743402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
744402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
745402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
746402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
747402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
748402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Everything is fine, call runtime.
749402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ecx);
750402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
751402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // key
752402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);  // return address
753402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
754402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
7556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(
7566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      IC_Utility(kKeyedLoadPropertyWithInterceptor));
7576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
758402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
759402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&slow);
760402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
7613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
7623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
764e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
765e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                   StrictModeFlag strict_mode) {
766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
7686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
7696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow, fast, array, extra, check_pixel_array;
773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map from the receiver.
7786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver does not require access checks.  We need
780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to do this because this generic stub does not perform map checks.
7817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
7827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch            1 << Map::kIsAccessCheckNeeded);
783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
7856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(ecx, Immediate(kSmiTagMask));
786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
7876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &array);
789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object.
7906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
7916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(below, &slow, not_taken);
792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Object case: Check key against length in the elements array.
794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSObject
7966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key (a smi)
7976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
798756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Check that the object is in fast mode and writable.
7996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
8007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &fast, taken);
802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
805e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  GenerateRuntimeSetProperty(masm, strict_mode);
806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check whether the elements is a pixel array.
808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
8096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: value
8107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ecx: key (a smi)
8116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
8126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
813e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  GenerateFastPixelArrayStore(masm,
814e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              edx,
815e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              ecx,
816e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              eax,
817e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              edi,
818e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              ebx,
819e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              false,
820e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              NULL,
821e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              &slow,
822e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              &slow,
823e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                              &slow);
824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Extra capacity case: Check if there is extra capacity to
826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // perform the store and update the length. Used for adding one
827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // element to the array by writing to array[array.length].
828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&extra);
829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
8306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSArray
8316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi.
8326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: receiver->elements, a FixedArray
8336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // flags: compare (ecx, edx.length())
834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
8357f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow, not_taken);
8376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Add 1 to receiver->length, and go to fast array write.
8386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(FieldOperand(edx, JSArray::kLengthOffset),
8397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch         Immediate(Smi::FromInt(1)));
840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&fast);
841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array case: Get the length and the elements array from the JS
843756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // array. Check that the array is in fast mode (and writable); if it
844756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // is the length is always a smi.
845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&array);
846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
8476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSArray
8486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi.
8496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
8506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the key against the length in the array, compute the
853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // address to store into and fall through to fast case.
8546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &extra, not_taken);
856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the store.
858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&fast);
859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
8606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key (a smi)
8616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
8626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: FixedArray receiver->elements
86325f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update write barrier for the elements array address.
865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(eax));
8666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ RecordWrite(edi, 0, edx, ecx);
867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// The generated code does not accept smi keys.
8727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch// The generated code falls through if both probes miss.
8737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochstatic void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
8747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch                                          int argc,
8759dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                          Code::Kind kind) {
876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
877e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
8787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- edx                 : receiver
879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
8809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  Label number, non_number, non_string, boolean, probe, miss;
881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
883b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  Code::Flags flags = Code::ComputeFlags(kind,
884b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                         NOT_IN_LOOP,
885b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                         MONOMORPHIC,
886b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                         Code::kNoExtraICState,
887b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                         NORMAL,
888b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                         argc);
889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the stub cache probing failed, the receiver might be a value.
892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // For value objects, we use the map of the prototype objects for
893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the corresponding JSValue for the cache and that is what we need
894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to probe.
895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for number.
897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &number, not_taken);
899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &non_number, taken);
901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&number);
902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::NUMBER_FUNCTION_INDEX, edx);
904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for string.
907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_number);
9087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &non_string, taken);
910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::STRING_FUNCTION_INDEX, edx);
912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for boolean.
915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_string);
916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::true_value());
917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &boolean, not_taken);
918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::false_value());
9199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ j(not_equal, &miss, taken);
920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&boolean);
921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache for the value object.
925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&probe);
926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
9279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ bind(&miss);
928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9318defd9ff6930b4e24729971a61cf7469daf119beSteve Blockstatic void GenerateFunctionTailCall(MacroAssembler* masm,
9328defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                     int argc,
9338defd9ff6930b4e24729971a61cf7469daf119beSteve Block                                     Label* miss) {
934e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
935e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
9368defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- edi                 : function
937e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
938e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
939e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
940e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
941e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
943e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the result is not a smi.
944e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ test(edi, Immediate(kSmiTagMask));
945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
947e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the value is a JavaScript function, fetching its map into eax.
948e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss, not_taken);
950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen// The generated code falls through if the call should be handled by runtime.
9579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic void GenerateCallNormal(MacroAssembler* masm, int argc) {
958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
959e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
960e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
961e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
962e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
963e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
9658defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label miss;
966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9708defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9728defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // eax: elements
9738defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // Search the dictionary placing the result in edi.
9748defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
9758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateFunctionTailCall(masm, argc, &miss);
9769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
9779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ bind(&miss);
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
981b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdochstatic void GenerateCallMiss(MacroAssembler* masm,
982b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             int argc,
983b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             IC::UtilityId id) {
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
985e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
986e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
987e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
988e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
989e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
9928defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (id == IC::kCallIC_Miss) {
9938defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ IncrementCounter(&Counters::call_miss, 1);
9948defd9ff6930b4e24729971a61cf7469daf119beSteve Block  } else {
9958defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ IncrementCounter(&Counters::keyed_call_miss, 1);
9968defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
9978defd9ff6930b4e24729971a61cf7469daf119beSteve Block
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter an internal frame.
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterInternalFrame();
1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the receiver and the name of the function.
1005a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(edx);
1006e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(ecx);
1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the entry.
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CEntryStub stub(1);
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Immediate(2));
10117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, Immediate(ExternalReference(IC_Utility(id))));
1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallStub(&stub);
1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move result to edi and exit the internal frame.
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edi, eax);
1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveInternalFrame();
1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the receiver is a global object of some sort.
10198defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // This can happen only for regular CallIC but not KeyedCallIC.
10208defd9ff6930b4e24729971a61cf7469daf119beSteve Block  if (id == IC::kCallIC_Miss) {
10218defd9ff6930b4e24729971a61cf7469daf119beSteve Block    Label invoke, global;
10228defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
10238defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ test(edx, Immediate(kSmiTagMask));
10248defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ j(zero, &invoke, not_taken);
10258defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
10268defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
10278defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
10288defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ j(equal, &global);
10298defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
10308defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ j(not_equal, &invoke);
10318defd9ff6930b4e24729971a61cf7469daf119beSteve Block
10328defd9ff6930b4e24729971a61cf7469daf119beSteve Block    // Patch the receiver on the stack.
10338defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ bind(&global);
10348defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
10358defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
10368defd9ff6930b4e24729971a61cf7469daf119beSteve Block    __ bind(&invoke);
10378defd9ff6930b4e24729971a61cf7469daf119beSteve Block  }
1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
10467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
10477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ecx                 : name
10487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0]              : return address
10497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
10507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ...
10517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
10527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
10537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Get the receiver of the function from the stack; 1 ~ return address.
10557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
10569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
10577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
10587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
10597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
10629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
10639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
10649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
10659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
10669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
10679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
10689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
10699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
10709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateCallNormal(masm, argc);
10717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
10727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
10737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10757f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
10769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
10779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
10789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
10799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
10809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
10819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
10829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
10839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
10847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
10857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
10867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
10897f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ----------- S t a t e -------------
10907f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ecx                 : name
10917f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[0]              : return address
10927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
10937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- ...
10947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //  -- esp[(argc + 1) * 4] : receiver
10957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // -----------------------------------
10967f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
10977f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Get the receiver of the function from the stack; 1 ~ return address.
10987f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
10997f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11007f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label do_call, slow_call, slow_load, slow_reload_receiver;
11017f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label check_number_dictionary, check_string, lookup_monomorphic_cache;
11027f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  Label index_smi, index_string;
11037f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11047f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check that the key is a smi.
11057f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ test(ecx, Immediate(kSmiTagMask));
11067f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ j(not_zero, &check_string, not_taken);
11077f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11087f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_smi);
11097f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Now the key is known to be a smi. This place is also jumped to from
11107f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // where a numeric string is converted to a smi.
11117f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11128defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
11138defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
11147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateFastArrayLoad(
11169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
11177f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1);
11187f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11197f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&do_call);
11207f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // receiver in edx is not used after this point.
11217f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ecx: key
11227f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // edi: function
11238defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateFunctionTailCall(masm, argc, &slow_call);
11247f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&check_number_dictionary);
11267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // eax: elements
11277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ecx: smi key
11287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Check whether the elements is a number dictionary.
11297f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CheckMap(eax, Factory::hash_table_map(), &slow_load, true);
11307f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, ecx);
11317f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ SmiUntag(ebx);
11327f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // ebx: untagged index
11337f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Receiver in edx will be clobbered, need to reload it on miss.
11349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateNumberDictionaryLoad(
11359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      masm, &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
11367f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1);
11377f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ jmp(&do_call);
11387f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11397f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&slow_reload_receiver);
11407f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
11417f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11427f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&slow_load);
11437f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // This branch is taken when calling KeyedCallIC_Miss is neither required
11447f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // nor beneficial.
11457f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1);
11467f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ EnterInternalFrame();
11477f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ push(ecx);  // save the key
11487f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ push(edx);  // pass the receiver
11497f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ push(ecx);  // pass the key
11507f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ CallRuntime(Runtime::kKeyedGetProperty, 2);
11517f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ pop(ecx);  // restore the key
11527f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ LeaveInternalFrame();
11537f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(edi, eax);
11547f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ jmp(&do_call);
11557f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11567f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&check_string);
11577f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
11587f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11597f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // The key is known to be a symbol.
11607f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // If the receiver is a regular JS object with slow properties then do
11617f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // a quick inline probe of the receiver's dictionary.
11627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Otherwise do the monomorphic cache probe.
11638defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateKeyedLoadReceiverCheck(
11648defd9ff6930b4e24729971a61cf7469daf119beSteve Block      masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
11657f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11667f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
11678defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ CheckMap(ebx, Factory::hash_table_map(), &lookup_monomorphic_cache, true);
11687f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11698defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
11707f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1);
11717f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ jmp(&do_call);
11727f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11737f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&lookup_monomorphic_cache);
11747f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1);
11759dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
11767f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Fall through on miss.
11777f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11787f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&slow_call);
11797f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // This branch is taken if:
11807f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - the receiver requires boxing or access check,
11817f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - the key is neither smi nor symbol,
11827f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - the value loaded is not a function,
11837f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // - there is hope that the runtime will create a monomorphic call stub
11847f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  //   that will get fetched next time.
11857f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ IncrementCounter(&Counters::keyed_call_generic_slow, 1);
11867f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
11877f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11887f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  __ bind(&index_string);
118980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  __ IndexFromHash(ebx, ecx);
11909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Now jump to the place where smi keys are handled.
11919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  __ jmp(&index_smi);
11927f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
11937f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11947f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
11957f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
11969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
11979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
11989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
11999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
12009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
12019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
12029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
12039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
1204e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  // Check if the name is a string.
1205e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Label miss;
1206e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ test(ecx, Immediate(kSmiTagMask));
1207e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(zero, &miss);
1208e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  Condition cond = masm->IsObjectStringType(ecx, eax, eax);
1209e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ j(NegateCondition(cond), &miss);
12109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  GenerateCallNormal(masm, argc);
1211e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ bind(&miss);
12127f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateMiss(masm, argc);
12137f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
12147f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12157f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12167f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdochvoid KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
12179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // ----------- S t a t e -------------
12189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ecx                 : name
12199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[0]              : return address
12209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
12219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- ...
12229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  -- esp[(argc + 1) * 4] : receiver
12239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // -----------------------------------
12249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
12257f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
12267f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch}
12277f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
12287f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1231402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
1237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1243402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateNormal(MacroAssembler* masm) {
1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1249402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
12538defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label miss;
1254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12558defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12578defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // edx: elements
1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Search the dictionary placing the result in eax.
12598defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12627f4d5bd8c03935e2c0cd412e561b8fc5a6a880aeBen Murdoch  // Cache miss: Jump to runtime.
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1264402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMiss(MacroAssembler* masm) {
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1270402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12758defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::load_miss, 1);
12768defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // receiver
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);  // name
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
12836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
12846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1289b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (V8::UseCrankshaft()) return false;
1290b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The address of the instruction following the call.
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the instruction following the call is not a test eax, nothing
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // was inlined.
1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (*test_instruction_address != Assembler::kTestEaxByte) return false;
1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The delta to the start of the map check instruction.
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The map address is the last 4 bytes of the 7-byte
1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand-immediate compare instruction, so we add 3 to get the
1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The offset is in the last 4 bytes of a six byte
1309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // memory-to-register move instruction, so we add 2 to get the
1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address offset_address =
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen// One byte opcode for mov ecx,0xXXXXXXXX.
1319f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch// Marks inlined contextual loads using all kinds of cells. Generated
1320f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch// code has the hole check:
1321f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   mov reg, <cell>
1322f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   mov reg, (<cell>, value offset)
1323f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   cmp reg, <the hole>
1324f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   je  slow
1325f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   ;; use reg
13260d5e116f6aee03185f237311a943491bb079a768Kristian Monsenstatic const byte kMovEcxByte = 0xB9;
13270d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
1328f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch// One byte opcode for mov edx,0xXXXXXXXX.
1329f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch// Marks inlined contextual loads using only "don't delete"
1330f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch// cells. Generated code doesn't have the hole check:
1331f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   mov reg, <cell>
1332f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   mov reg, (<cell>, value offset)
1333f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch//   ;; use reg
1334f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochstatic const byte kMovEdxByte = 0xBA;
1335f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
13360d5e116f6aee03185f237311a943491bb079a768Kristian Monsenbool LoadIC::PatchInlinedContextualLoad(Address address,
13370d5e116f6aee03185f237311a943491bb079a768Kristian Monsen                                        Object* map,
1338f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                        Object* cell,
1339f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                        bool is_dont_delete) {
1340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (V8::UseCrankshaft()) return false;
1341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
13420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // The address of the instruction following the call.
13430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  Address mov_instruction_address =
13440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      address + Assembler::kCallTargetAddressOffset;
1345f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // If the instruction following the call is not a mov ecx/edx,
1346f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // nothing was inlined.
1347f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  byte b = *mov_instruction_address;
1348f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if (b != kMovEcxByte && b != kMovEdxByte) return false;
1349f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // If we don't have the hole check generated, we can only support
1350f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // "don't delete" cells.
1351f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if (b == kMovEdxByte && !is_dont_delete) return false;
13520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
13530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  Address delta_address = mov_instruction_address + 1;
13540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // The delta to the start of the map check instruction.
13550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int delta = *reinterpret_cast<int*>(delta_address);
13560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
13570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // The map address is the last 4 bytes of the 7-byte
13580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // operand-immediate compare instruction, so we add 3 to get the
13590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // offset to the last 4 bytes.
13600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  Address map_address = mov_instruction_address + delta + 3;
13610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  *(reinterpret_cast<Object**>(map_address)) = map;
13620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
13630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // The cell is in the last 4 bytes of a five byte mov reg, imm32
13640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // instruction, so we add 1 to get the offset to the last 4 bytes.
13650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  Address offset_address =
13660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      mov_instruction_address + delta + kOffsetToLoadInstruction + 1;
13670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  *reinterpret_cast<Object**>(offset_address) = cell;
13680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  return true;
13690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}
13700d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
13710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
137250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsenbool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
1373b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (V8::UseCrankshaft()) return false;
1374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
137550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // The address of the instruction following the call.
137650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address test_instruction_address =
137750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen      address + Assembler::kCallTargetAddressOffset;
137850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
137950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // If the instruction following the call is not a test eax, nothing
138050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // was inlined.
1381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (*test_instruction_address != Assembler::kTestEaxByte) return false;
138250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
138350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Extract the encoded deltas from the test eax instruction.
138450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address encoded_offsets_address = test_instruction_address + 1;
138550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  int encoded_offsets = *reinterpret_cast<int*>(encoded_offsets_address);
138650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  int delta_to_map_check = -(encoded_offsets & 0xFFFF);
138750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  int delta_to_record_write = encoded_offsets >> 16;
138850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
138950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Patch the map to check. The map address is the last 4 bytes of
139050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // the 7-byte operand-immediate compare instruction.
139150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address map_check_address = test_instruction_address + delta_to_map_check;
139250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address map_address = map_check_address + 3;
139350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  *(reinterpret_cast<Object**>(map_address)) = map;
139450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
139550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Patch the offset in the store instruction. The offset is in the
139650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // last 4 bytes of a six byte register-to-memory move instruction.
139750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  Address offset_address =
139850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen      map_check_address + StoreIC::kOffsetToStoreInstruction + 2;
139950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // The offset should have initial value (kMaxInt - 1), cleared value
140050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // (-1) or we should be clearing the inlined version.
140150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt - 1 ||
140250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         *reinterpret_cast<int*>(offset_address) == -1 ||
140350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         (offset == 0 && map == Heap::null_value()));
140450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
140550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
140650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // Patch the offset in the write-barrier code. The offset is the
140750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // last 4 bytes of a six byte lea instruction.
140850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  offset_address = map_check_address + delta_to_record_write + 2;
140950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // The offset should have initial value (kMaxInt), cleared value
141050ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  // (-1) or we should be clearing the inlined version.
141150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  ASSERT(*reinterpret_cast<int*>(offset_address) == kMaxInt ||
141250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         *reinterpret_cast<int*>(offset_address) == -1 ||
141350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen         (offset == 0 && map == Heap::null_value()));
141450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
141550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
141650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen  return true;
141750ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen}
141850ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
141950ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
1420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool PatchInlinedMapCheck(Address address, Object* map) {
1421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (V8::UseCrankshaft()) return false;
1422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The keyed load has a fast inlined case if the IC call instruction
1426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is immediately followed by a test instruction.
1427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (*test_instruction_address != Assembler::kTestEaxByte) return false;
1428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch the offset from the test instruction to the map cmp
1430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction.  This offset is stored in the last 4 bytes of the 5
1431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // byte test instruction.
1432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the map address.  The map address is in the last 4 bytes
1435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the 7-byte operand-immediate compare instruction, so we add 3
1436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the offset to get the map address.
1437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the map check.
1439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1456402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1457402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14618defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::keyed_load_miss, 1);
14628defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1463402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ebx);
1464402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1465402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // name
1466402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ebx);  // return address
1467402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1468402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
14696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
14706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
1471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1474402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1476402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1477402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1482402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // name
1484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
14876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Blockvoid StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1492e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                  StrictModeFlag strict_mode) {
1493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
14964515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
15021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                         MONOMORPHIC,
1503e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                         strict_mode);
1504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
15074515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  GenerateMiss(masm);
1508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15114515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid StoreIC::GenerateMiss(MacroAssembler* masm) {
1512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
15154515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
15204515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(edx);
1521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
1522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);
1523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);
1524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
15266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
15276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 3, 1);
15286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
15296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
153150ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen// The offset from the inlined patch site to the start of the inlined
153250ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen// store instruction.  It is 7 bytes (test reg, imm) plus 6 bytes (jne
153350ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen// slow_label).
153450ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsenconst int StoreIC::kOffsetToStoreInstruction = 13;
153550ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
153650ef84f5fad2def87d3fbc737bec4a32711fdef4Kristian Monsen
15376ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockvoid StoreIC::GenerateArrayLength(MacroAssembler* masm) {
15386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
15396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : value
15406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : name
15416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
15426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[0] : return address
15436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
15446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
15456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // This accepts as a receiver anything JSObject::SetElementsLength accepts
15466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // (currently anything except for external and pixel arrays which means
15476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // anything with elements of FixedArray type.), but currently is restricted
15486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // to JSArray.
15496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Value must be a number, but only smis are accepted as the most common case.
15506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
15526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register receiver = edx;
15546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register value = eax;
15556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register scratch = ebx;
15566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the receiver isn't a smi.
15586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(receiver, Immediate(kSmiTagMask));
15596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(zero, &miss, not_taken);
15606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the object is a JS array.
15626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
15636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &miss, not_taken);
15646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that elements are FixedArray.
1566756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // We rely on StoreIC_ArrayLength below to deal with all types of
1567756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // fast elements (including COW).
15686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
15696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
15706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &miss, not_taken);
15716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that value is a smi.
15736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(value, Immediate(kSmiTagMask));
15746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_zero, &miss, not_taken);
15756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Prepare tail call to StoreIC_ArrayLength.
15776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(scratch);
15786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(receiver);
15796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(value);
15806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(scratch);  // return address
15816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
15836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
15846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
15866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateMiss(masm);
1588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15918defd9ff6930b4e24729971a61cf7469daf119beSteve Blockvoid StoreIC::GenerateNormal(MacroAssembler* masm) {
15928defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // ----------- S t a t e -------------
15938defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- eax    : value
15948defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- ecx    : name
15958defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- edx    : receiver
15968defd9ff6930b4e24729971a61cf7469daf119beSteve Block  //  -- esp[0] : return address
15978defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // -----------------------------------
15988defd9ff6930b4e24729971a61cf7469daf119beSteve Block
15998defd9ff6930b4e24729971a61cf7469daf119beSteve Block  Label miss, restore_miss;
16008defd9ff6930b4e24729971a61cf7469daf119beSteve Block
16018defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
16028defd9ff6930b4e24729971a61cf7469daf119beSteve Block
16038defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // A lot of registers are needed for storing to slow case
16048defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // objects. Push and restore receiver but rely on
16058defd9ff6930b4e24729971a61cf7469daf119beSteve Block  // GenerateDictionaryStore preserving the value and name.
16068defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ push(edx);
16078defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
16088defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ Drop(1);
16098defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::store_normal_hit, 1);
16108defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ ret(0);
16118defd9ff6930b4e24729971a61cf7469daf119beSteve Block
16128defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&restore_miss);
16138defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ pop(edx);
16148defd9ff6930b4e24729971a61cf7469daf119beSteve Block
16158defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ bind(&miss);
16168defd9ff6930b4e24729971a61cf7469daf119beSteve Block  __ IncrementCounter(&Counters::store_normal_miss, 1);
16178defd9ff6930b4e24729971a61cf7469daf119beSteve Block  GenerateMiss(masm);
16188defd9ff6930b4e24729971a61cf7469daf119beSteve Block}
16198defd9ff6930b4e24729971a61cf7469daf119beSteve Block
16208defd9ff6930b4e24729971a61cf7469daf119beSteve Block
1621e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1622e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                  StrictModeFlag strict_mode) {
1623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // ----------- S t a t e -------------
1624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- eax    : value
1625b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- ecx    : name
1626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- edx    : receiver
1627b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  //  -- esp[0] : return address
1628b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // -----------------------------------
1629b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ pop(ebx);
1630b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(edx);
1631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(ecx);
1632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  __ push(eax);
1633e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ push(Immediate(Smi::FromInt(NONE)));  // PropertyAttributes
1634e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ push(Immediate(Smi::FromInt(strict_mode)));
1635e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ push(ebx);  // return address
1636b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Do tail-call to runtime routine.
1638e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1639b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1640b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1641b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1642e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochvoid KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1643e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                              StrictModeFlag strict_mode) {
1644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
16466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
16476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
1648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(ebx);
16526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
1653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
16546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(eax);
1655e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ push(Immediate(Smi::FromInt(NONE)));         // PropertyAttributes
1656e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ push(Immediate(Smi::FromInt(strict_mode)));  // Strict mode.
1657e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ push(ebx);   // return address
1658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
1660e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch  __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
1661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1664402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
16676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
16686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
1669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(ebx);
16736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
1674402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);
16756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(eax);
16766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(ebx);
1677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
16796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
16806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 3, 1);
1681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
1685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben MurdochCondition CompareIC::ComputeCondition(Token::Value op) {
1688b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  switch (op) {
1689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::EQ_STRICT:
1690b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::EQ:
1691b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return equal;
1692b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::LT:
1693b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return less;
1694b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::GT:
1695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Reverse left and right operands to obtain ECMA-262 conversion order.
1696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return less;
1697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::LTE:
1698b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      // Reverse left and right operands to obtain ECMA-262 conversion order.
1699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return greater_equal;
1700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    case Token::GTE:
1701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return greater_equal;
1702b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    default:
1703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      UNREACHABLE();
1704b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return no_condition;
1705b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1706b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochstatic bool HasInlinedSmiCode(Address address) {
1710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The address of the instruction following the call.
1711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Address test_instruction_address =
1712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      address + Assembler::kCallTargetAddressOffset;
1713b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If the instruction following the call is not a test al, nothing
1715b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // was inlined.
1716b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  return *test_instruction_address == Assembler::kTestAlByte;
1717b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1721b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  HandleScope scope;
1722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Handle<Code> rewritten;
1723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  State previous_state = GetState();
1724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
1726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (state == GENERIC) {
1727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
1728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    rewritten = stub.GetCode();
1729b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  } else {
1730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ICCompareStub stub(op_, state);
1731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    rewritten = stub.GetCode();
1732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  set_target(*rewritten);
1734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#ifdef DEBUG
1736b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_ic) {
1737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("[CompareIC (%s->%s)#%s]\n",
1738b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           GetStateName(previous_state),
1739b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           GetStateName(state),
1740b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           Token::Name(op_));
1741b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch#endif
1743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Activate inlined smi code.
1745b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (previous_state == UNINITIALIZED) {
1746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PatchInlinedSmiCode(address());
1747b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1751b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochvoid PatchInlinedSmiCode(Address address) {
1752b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The address of the instruction following the call.
1753b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Address test_instruction_address =
1754b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      address + Assembler::kCallTargetAddressOffset;
1755b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1756b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // If the instruction following the call is not a test al, nothing
1757b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // was inlined.
1758b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (*test_instruction_address != Assembler::kTestAlByte) {
1759b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ASSERT(*test_instruction_address == Assembler::kNopByte);
1760b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    return;
1761b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1762b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Address delta_address = test_instruction_address + 1;
1764b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // The delta to the start of the map check instruction and the
1765b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // condition code uses at the patched jump.
1766b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if (FLAG_trace_ic) {
1768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    PrintF("[  patching ic at %p, test=%p, delta=%d\n",
1769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch           address, test_instruction_address, delta);
1770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Patch with a short conditional jump. There must be a
1773b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // short jump-if-carry/not-carry at this position.
1774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Address jmp_address = test_instruction_address - delta;
1775b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
1776b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch         *jmp_address == Assembler::kJcShortOpcode);
1777b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  Condition cc = *jmp_address == Assembler::kJncShortOpcode
1778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      ? not_zero
1779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      : zero;
1780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
1781b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1784a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
1785f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke
1786f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke#endif  // V8_TARGET_ARCH_IA32
1787