ic-ia32.cc revision 25f6136652d8341ed047e7fc1a450af5bd218ea9
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2006-2008 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
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen-inl.h"
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "ic-inl.h"
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "runtime.h"
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "stub-cache.h"
34d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#include "utils.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace v8 {
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace internal {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// ----------------------------------------------------------------------------
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Static IC stub generators.
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#define __ ACCESS_MASM(masm)
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Helper function used to load a property from a dictionary backing storage.
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This function may return false negatives, so miss_label
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// must always call a backup property load that is complete.
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// This function is safe to call if the receiver has fast properties,
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// or if name is not a symbol, and will jump to the miss_label in that case.
51e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkestatic void GenerateDictionaryLoad(MacroAssembler* masm,
52e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   Label* miss_label,
53402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                   Register receiver,
54402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                                   Register name,
55e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   Register r0,
56e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   Register r1,
57e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   Register r2,
58e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                                   DictionaryCheck check_dictionary) {
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Register use:
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
61402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // name - holds the name of the property and is unchanged.
62402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // receiver - holds the receiver and is unchanged.
63402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Scratch registers:
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r0   - used to hold the property dictionary.
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
66402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // r1   - used for the index into the property dictionary
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //      - holds the result on exit.
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r2   - used to hold the capacity of the property dictionary.
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label done;
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for the absence of an interceptor.
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Load the map into r0.
75402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Bail out if the receiver has a named interceptor.
786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(FieldOperand(r0, Map::kBitFieldOffset),
796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          Immediate(1 << Map::kHasNamedInterceptor));
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, miss_label, not_taken);
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Bail out if we have a JS global proxy object.
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, miss_label, not_taken);
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Possible work-around for http://crbug.com/16276.
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, miss_label, not_taken);
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, miss_label, not_taken);
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load properties array.
94402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
95e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
96e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the properties array is a dictionary.
97e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (check_dictionary == CHECK_DICTIONARY) {
98e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
99e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke           Immediate(Factory::hash_table_map()));
100e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(not_equal, miss_label);
101e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the capacity mask.
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kCapacityOffset =
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kCapacityIndex * kPointerSize;
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r2, FieldOperand(r0, kCapacityOffset));
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ shr(r2, kSmiTagSize);  // convert smi to int
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ dec(r2);
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate an unrolled loop that performs a few probes before
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // giving up. Measurements done on Gmail indicate that 2 probes
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // cover ~93% of loads from dictionaries.
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kProbes = 4;
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kElementsStartOffset =
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kProbes; i++) {
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the masked index: (hash + i + i * i) & mask.
120d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ shr(r1, String::kHashShift);
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i > 0) {
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ and_(r1, Operand(r2));
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Scale the index by multiplying by the entry size.
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(StringDictionary::kEntrySize == 3);
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if the key is identical to the name.
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(name,
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i != kProbes - 1) {
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(equal, &done, taken);
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(not_equal, miss_label, not_taken);
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the value is a normal property.
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, miss_label, not_taken);
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the value at the masked, scaled index.
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kValueOffset = kElementsStartOffset + kPointerSize;
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1546ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockstatic void GenerateNumberDictionaryLoad(MacroAssembler* masm,
1556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Label* miss,
1566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register elements,
1576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register key,
1586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r0,
1596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r1,
1606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                         Register r2) {
1616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Register use:
1626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // elements - holds the slow-case elements of the receiver and is unchanged.
1646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // key      - holds the smi key on entry and is unchanged if a branch is
1666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //            performed to the miss label. If the load succeeds and we
1676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //            fall through, key holds the result on exit.
1686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Scratch registers:
1706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r0 - holds the untagged key on entry and holds the hash once computed.
1726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r1 - used to hold the capacity mask of the dictionary
1746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // r2 - used for the index into the dictionary.
1766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label done;
1776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
1786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Compute the hash code from the untagged key.  This must be kept in sync
1796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // with ComputeIntegerHash in utils.h.
1806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
1816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = ~hash + (hash << 15);
1826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
1836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ not_(r0);
1846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shl(r1, 15);
1856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(r0, Operand(r1));
1866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 12);
1876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
1886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 12);
1896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
1906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash + (hash << 2);
1916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ lea(r0, Operand(r0, r0, times_4, 0));
1926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 4);
1936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
1946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 4);
1956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
1966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash * 2057;
1976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ imul(r0, r0, 2057);
1986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // hash = hash ^ (hash >> 16);
1996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, r0);
2006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, 16);
2016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ xor_(r0, Operand(r1));
2026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Compute capacity mask.
2046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
2056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ shr(r1, kSmiTagSize);  // convert smi to int
2066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ dec(r1);
2076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Generate an unrolled loop that performs a few probes before giving up.
2096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kProbes = 4;
2106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  for (int i = 0; i < kProbes; i++) {
2116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Use r2 for index calculations and keep the hash intact in r0.
2126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ mov(r2, r0);
2136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Compute the masked index: (hash + i + i * i) & mask.
2146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (i > 0) {
2156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
2166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
2176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ and_(r2, Operand(r1));
2186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Scale the index by multiplying by the entry size.
2206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(NumberDictionary::kEntrySize == 3);
2216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ lea(r2, Operand(r2, r2, times_2, 0));  // r2 = r2 * 3
2226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // Check if the key matches.
2246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ cmp(key, FieldOperand(elements,
2256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             r2,
2266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             times_pointer_size,
2276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                             NumberDictionary::kElementsStartOffset));
2286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    if (i != (kProbes - 1)) {
2296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(equal, &done, taken);
2306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    } else {
2316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ j(not_equal, miss, not_taken);
2326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    }
2336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
2346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&done);
2366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the value is a normal propety.
2376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kDetailsOffset =
2386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
2396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT_EQ(NORMAL, 0);
2406ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
2416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
2426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_zero, miss);
2436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Get the value at the masked, scaled index.
2456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  const int kValueOffset =
2466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      NumberDictionary::kElementsStartOffset + kPointerSize;
2476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
2486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
2496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
2506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The offset from the inlined patch site to the start of the
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// inlined load instruction.  It is 7 bytes (test eax, imm) plus
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6 bytes (jne slow_label).
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst int LoadIC::kOffsetToLoadInstruction = 13;
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateArrayLength(MacroAssembler* masm) {
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
259402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateStringLength(MacroAssembler* masm) {
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
273402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
279402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
287402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
301402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
302402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
305e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label slow, check_string, index_int, index_string;
306e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label check_pixel_array, probe_dictionary;
3076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label check_number_dictionary;
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
310402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map of the receiver.
314402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
315d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
316d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check bit field.
317402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
318d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ test(ebx, Immediate(kSlowCaseBitFieldMask));
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object EXCEPT JS Value type.
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In the case that the object is a value-wrapper object,
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we enter the runtime system to make sure that indexing
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // into string objects work as intended.
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
325402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
326402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(below, &slow, not_taken);
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &check_string, not_taken);
330402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, eax);
331402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiUntag(ebx);
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the elements array of the object.
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&index_int);
334402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is in fast mode (not dictionary).
336402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true);
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key (index) is within bounds.
338402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the load.
341402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(ecx, ebx, times_4, FixedArray::kHeaderSize));
342402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(Operand(ecx), Immediate(Factory::the_hole_value()));
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In case the loaded value is the_hole we have to consult GetProperty
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to ensure the prototype chain is searched.
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &slow);
346402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, ecx);
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
351402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check whether the elements is a pixel array.
352402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
353402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: untagged index
354402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
355402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx: elements
3566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true);
357402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
359402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
360402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
361402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiTag(eax);
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&check_number_dictionary);
3656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check whether the elements is a number dictionary.
3666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
3676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ebx: untagged index
3686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: key
3696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: elements
3706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
3716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label slow_pop_receiver;
3726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Push receiver on the stack to free up a register for the dictionary
3736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // probing.
3746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
3756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateNumberDictionaryLoad(masm,
3766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               &slow_pop_receiver,
3776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               ecx,
3786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               eax,
3796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               ebx,
3806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               edx,
3816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                               edi);
3826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Pop receiver before returning.
3836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(edx);
3846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);
3856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
3866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&slow_pop_receiver);
3876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Pop the receiver from the stack and jump to runtime.
3886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(edx);
3896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
391402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Slow case: jump to runtime.
392402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
393402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
395402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_string);
398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The key is not a smi.
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Is it a string?
400402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
401402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
402402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Is the string an array index, with cached numeric value?
405d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(String::kIsArrayIndexMask));
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &index_string, not_taken);
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
409e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Is the string a symbol?
410402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset));
411e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kSymbolTag != 0);
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(kIsSymbolMask));
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
414e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
415e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If the receiver is a fast-case object, check the keyed lookup
416402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // cache. Otherwise probe the dictionary.
417402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
418e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
419e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke         Immediate(Factory::hash_table_map()));
420e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &probe_dictionary);
421e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
422e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the map of the receiver, compute the keyed lookup cache hash
423e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // based on 32 bits of the map pointer and the string hash.
424402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
425402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, ebx);
426402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(ecx, KeyedLookupCache::kMapHashShift);
427402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
428402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(edi, String::kHashShift);
429402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ xor_(ecx, Operand(edi));
430402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(ecx, KeyedLookupCache::kCapacityMask);
431e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
432e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the key (consisting of map and symbol) from the cache and
433e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // check for match.
434e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_keys
435e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_keys();
436402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, ecx);
437e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ shl(edi, kPointerSizeLog2 + 1);
438e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
439e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
440e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ add(Operand(edi), Immediate(kPointerSize));
441402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
442e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
443e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
444e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Get field offset and check that it is an in-object property.
445402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx     : receiver
446402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx     : receiver's map
447402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax     : key
448402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx     : lookup cache index
449e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_field_offsets
450e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_field_offsets();
451402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi,
452402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
453402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
454402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(edi, Operand(ecx));
455e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(above_equal, &slow);
456e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
457e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load in-object property.
458402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ sub(edi, Operand(ecx));
459402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
460402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ add(ecx, Operand(edi));
461402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
462e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(0);
463e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
464e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Do a quick inline probe of the receiver's dictionary, if it
465e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // exists.
466e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&probe_dictionary);
467e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateDictionaryLoad(masm,
468e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         &slow,
469e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         edx,
470e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         eax,
471402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ebx,
472402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ecx,
473402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         edi,
474e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         DICTIONARY_CHECK_DONE);
4756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(eax, ecx);
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
478e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
479d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // If the hash field contains an array index pick it out. The assert checks
480d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // that the constants for the maximum number of digits for an array index
481d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // cached in the hash field and the number of bits reserved for it does not
482d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // conflict.
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
484d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block         (1 << String::kArrayIndexValueBits));
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&index_string);
486402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(ebx, String::kArrayIndexHashMask);
487402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(ebx, String::kHashShift);
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&index_int);
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
492e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid KeyedLoadIC::GenerateString(MacroAssembler* masm) {
493e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
4946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : key (index)
495402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
496e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0] : return address
497e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
4986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
4996ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label index_not_smi;
5006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label index_out_of_range;
5016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label slow_char_code;
5026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label got_char_code;
5036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register receiver = edx;
5056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register index = eax;
5066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register code = ebx;
5076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register scratch = ecx;
5086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  StringHelper::GenerateFastCharCodeAt(masm,
5106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       receiver,
5116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       index,
5126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       scratch,
5136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       code,
5146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       &miss,  // When not a string.
5156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       &index_not_smi,
5166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       &index_out_of_range,
5176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block                                       &slow_char_code);
5186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // If we didn't bail out, code register contains smi tagged char
5196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // code.
5206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&got_char_code);
5216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  StringHelper::GenerateCharFromCode(masm, code, eax, JUMP_FUNCTION);
5226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#ifdef DEBUG
5236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Abort("Unexpected fall-through from char from code tail call");
5246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#endif
5256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check if key is a heap number.
5276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&index_not_smi);
5286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(index, Factory::heap_number_map(), &miss, true);
5296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
5306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Push receiver and key on the stack (now that we know they are a
5316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // string and a number), and call runtime.
5326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&slow_char_code);
5336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ EnterInternalFrame();
5346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(receiver);
5356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(index);
5366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CallRuntime(Runtime::kStringCharCodeAt, 2);
5376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ASSERT(!code.is(eax));
5386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(code, eax);
5396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ LeaveInternalFrame();
540e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
5416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check if the runtime call returned NaN char code. If yes, return
5426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // undefined. Otherwise, we can continue.
5436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  if (FLAG_debug_code) {
5446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    ASSERT(kSmiTag == 0);
5456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ test(code, Immediate(kSmiTagMask));
5466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ j(zero, &got_char_code);
5476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ mov(scratch, FieldOperand(code, HeapObject::kMapOffset));
5486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ cmp(scratch, Factory::heap_number_map());
5496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ Assert(equal, "StringCharCodeAt must return smi or heap number");
5506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  }
5516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(code, Factory::nan_value());
5526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &got_char_code);
5536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&index_out_of_range);
5546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ Set(eax, Immediate(Factory::undefined_value()));
5556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);
556e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
557e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&miss);
558e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm);
559e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
560e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
561e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
5623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
5633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        ExternalArrayType array_type) {
5643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ----------- S t a t e -------------
565402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
566402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
5673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[0] : return address
5683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // -----------------------------------
5693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label slow, failed_allocation;
5703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object isn't a smi.
572402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
5733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &slow, not_taken);
5743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the key is a smi.
5763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(eax, Immediate(kSmiTagMask));
5773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow, not_taken);
5783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the map of the receiver.
580402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
5813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the receiver does not require access checks.  We need
5823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // to check this explicitly since this generic stub does not perform
5833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // map checks.
584402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
5853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
5863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow, not_taken);
5873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
588402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
5893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow, not_taken);
5903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the elements array is the appropriate type of
5923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ExternalArray.
593402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
5943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
595402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
5963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(map));
5973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow, not_taken);
5983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
599402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key, known to be a smi.
600402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver, known to be a JSObject.
601402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: elements object, known to be an external array.
6023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the index is in range.
603402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, eax);
604402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiUntag(ecx);  // Untag the index.
605402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
6063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Unsigned comparison catches both negative and too-large values.
6073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(above_equal, &slow);
6083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
609402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
610402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: base pointer of external storage
6113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (array_type) {
6123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalByteArray:
613402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
6143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedByteArray:
616402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
6173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalShortArray:
619402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
6203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedShortArray:
622402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
6233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalIntArray:
6253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedIntArray:
626402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ mov(ecx, Operand(ebx, ecx, times_4, 0));
6273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalFloatArray:
629402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ fld_s(Operand(ebx, ecx, times_4, 0));
6303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    default:
6323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
6333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
6343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
6353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
6363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // For integer array types:
637402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx: value
6383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // For floating-point array type:
6393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // FP(0): value
6403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
6413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (array_type == kExternalIntArray ||
6423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      array_type == kExternalUnsignedIntArray) {
6433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // For the Int and UnsignedInt array types, we need to see whether
6443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // the value can be represented in a Smi. If not, we need to convert
6453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // it to a HeapNumber.
6463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label box_int;
6473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type == kExternalIntArray) {
648402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ cmp(ecx, 0xC0000000);
649402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ j(sign, &box_int);
6503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
6513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ASSERT_EQ(array_type, kExternalUnsignedIntArray);
6523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // The test is different for unsigned int values. Since we need
653402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // the value to be in the range of a positive smi, we can't
6543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // handle either of the top two bits being set in the value.
655402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ test(ecx, Immediate(0xC0000000));
6563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ j(not_zero, &box_int);
6573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
6583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
659402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
660402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiTag(eax);
6613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
6623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
6633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&box_int);
6643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
6653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Allocate a HeapNumber for the int and perform int-to-double
6663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // conversion.
6673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type == kExternalIntArray) {
668402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ push(ecx);
6693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_s(Operand(esp, 0));
670402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
6713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
6723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ASSERT(array_type == kExternalUnsignedIntArray);
6733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Need to zero-extend the value.
6743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // There's no fild variant for unsigned values, so zero-extend
6753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // to a 64-bit int manually.
6763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(Immediate(0));
677402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ push(ecx);
6783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_d(Operand(esp, 0));
679402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
680402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
6813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
6823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // FP(0): value
683402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
6843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Set the value.
685402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
6863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
6873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
6883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else if (array_type == kExternalFloatArray) {
6893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // For the floating-point array type, we need to always allocate a
6903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // HeapNumber.
691402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
6923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Set the value.
693402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
6943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
6953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
6963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
697402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
698402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiTag(eax);
6993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
7003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
7013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If we fail allocation of the HeapNumber, we still have a value on
7033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // top of the FPU stack. Remove it.
7043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&failed_allocation);
7053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ ffree();
7063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fincstp();
7073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Fall through to slow case.
7083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
709402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Slow case: Load key and receiver from stack and jump to runtime.
7103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&slow);
7113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
712402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
713402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
714402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
715402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
716402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
717402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
718402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
719402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
720402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0] : return address
721402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
722402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label slow;
723402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
724402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the receiver isn't a smi.
725402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
726402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(zero, &slow, not_taken);
727402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
728402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the key is a smi.
729402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(eax, Immediate(kSmiTagMask));
730402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
731402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
732402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the map of the receiver.
733402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
734402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
735402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that it has indexed interceptor and access checks
736402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // are not enabled for this object.
737402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
738402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
739402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
740402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
741402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
742402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Everything is fine, call runtime.
743402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ecx);
744402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
745402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // key
746402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);  // return address
747402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
748402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
7496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(
7506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      IC_Utility(kKeyedLoadPropertyWithInterceptor));
7516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
752402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
753402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&slow);
754402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
7553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
7563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
7616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
7626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow, fast, array, extra, check_pixel_array;
766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map from the receiver.
7716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver does not require access checks.  We need
773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to do this because this generic stub does not perform map checks.
7746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
7786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(ecx, Immediate(kSmiTagMask));
779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
7806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, JS_ARRAY_TYPE);
781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &array);
782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object.
7836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
7846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(below, &slow, not_taken);
785a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
786a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Object case: Check key against length in the elements array.
787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSObject
7896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key (a smi)
7906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is in fast mode (not dictionary).
7926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
7936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, Operand(ecx));
7946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ebx);
7956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &fast, taken);
797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
800402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeSetProperty(masm);
801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check whether the elements is a pixel array.
803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
8046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: value
8056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key
8066ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
8076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
8086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the value is a smi. If a conversion is needed call into the
810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // runtime to convert and clamp.
811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow);
8136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, ecx);
8146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ebx);
8156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
8176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ecx, eax);  // Save the value. Key is not longer needed.
8186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ecx);
819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Clamp the value to [0..255].
8203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label done;
8216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ test(ecx, Immediate(0xFFFFFF00));
822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(zero, &done);
8236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ setcc(negative, ecx);  // 1 if negative, 0 if positive.
8246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ dec_b(ecx);  // 0 if negative, 255 if positive.
825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&done);
826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
8276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
8286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
8296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);  // Return value in eax.
830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Extra capacity case: Check if there is extra capacity to
832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // perform the store and update the length. Used for adding one
833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // element to the array by writing to array[array.length].
834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&extra);
835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
8366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSArray
8376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi.
8386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: receiver->elements, a FixedArray
8396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // flags: compare (ecx, edx.length())
840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
8416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, ecx);
8426ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ebx);  // untag
8436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow, not_taken);
8456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Add 1 to receiver->length, and go to fast array write.
8466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ add(FieldOperand(edx, JSArray::kLengthOffset),
8476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block         Immediate(1 << kSmiTagSize));
848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&fast);
849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array case: Get the length and the elements array from the JS
851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array. Check that the array is in fast mode; if it is the
852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // length is always a smi.
853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&array);
854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
8556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSArray
8566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi.
8576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
8586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the key against the length in the array, compute the
861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // address to store into and fall through to fast case.
8626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // Compare smis.
863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &extra, not_taken);
864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
865a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the store.
866a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&fast);
867a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
8686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key (a smi)
8696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
8706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: FixedArray receiver->elements
87125f6136652d8341ed047e7fc1a450af5bd218ea9Kristian Monsen  __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update write barrier for the elements array address.
873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(eax));
8746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ RecordWrite(edi, 0, edx, ecx);
875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
8793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
8803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                         ExternalArrayType array_type) {
8813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ----------- S t a t e -------------
8823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- eax    : value
8836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
8846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
8853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[0] : return address
8863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // -----------------------------------
8873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label slow, check_heap_number;
8883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object isn't a smi.
8903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(edx, Immediate(kSmiTagMask));
8913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &slow);
8923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the map from the receiver.
8936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
8943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the receiver does not require access checks.  We need
8953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // to do this because this generic stub does not perform map checks.
8966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
8973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
8983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow);
8993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the key is a smi.
9006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(ecx, Immediate(kSmiTagMask));
9013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow);
9023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the instance type from the map of the receiver.
9036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpInstanceType(edi, JS_OBJECT_TYPE);
9043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
9053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the elements array is the appropriate type of
9073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ExternalArray.
9083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // eax: value
9096ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver, a JSObject
9106ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key, a smi
9116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
9126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
9136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block              &slow, true);
9143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the index is in range.
9166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ebx, ecx);
9176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ebx);
9186ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
9193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Unsigned comparison catches both negative and too-large values.
9203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(above_equal, &slow);
9213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Handle both smis and HeapNumbers in the fast path. Go to the
9233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // runtime for all other kinds of values.
9243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // eax: value
9256ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
9266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key
9276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
9283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: untagged index
9293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(eax, Immediate(kSmiTagMask));
9303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &check_heap_number);
9313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // smi case
9326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(ecx, eax);  // Preserve the value in eax.  Key is no longer needed.
9336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ SmiUntag(ecx);
9346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
9353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ecx: base pointer of external storage
9363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (array_type) {
9373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalByteArray:
9383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedByteArray:
9396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
9403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
9413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalShortArray:
9423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedShortArray:
9436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
9443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
9453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalIntArray:
9463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedIntArray:
9476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ mov(Operand(edi, ebx, times_4, 0), ecx);
9483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
9493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalFloatArray:
9503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Need to perform int-to-float conversion.
9516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ push(ecx);
9523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_s(Operand(esp, 0));
9536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ pop(ecx);
9546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ fstp_s(Operand(edi, ebx, times_4, 0));
9553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
9563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    default:
9573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
9583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
9593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
9606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ ret(0);  // Return the original value.
9613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&check_heap_number);
9636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // eax: value
9646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edx: receiver
9656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ecx: key
9666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: elements array
9676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ebx: untagged index
9683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
9693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(Factory::heap_number_map()));
9703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
9713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // The WebGL specification leaves the behavior of storing NaN and
9733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // +/-Infinity into integer arrays basically undefined. For more
9743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // reproducible behavior, convert these to zero.
9753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
9766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
9773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: untagged index
9786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // edi: base pointer of external storage
9793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // top of FPU stack: value
9803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (array_type == kExternalFloatArray) {
9816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ fstp_s(Operand(edi, ebx, times_4, 0));
9823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
9833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
9843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Need to perform float-to-int conversion.
9853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Test the top of the FP stack for NaN.
9863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label is_nan;
9873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fucomi(0);
9883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ j(parity_even, &is_nan);
9893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type != kExternalUnsignedIntArray) {
9916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ push(ecx);  // Make room on stack
9923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fistp_s(Operand(esp, 0));
9936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ pop(ecx);
9943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
9953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // fistp stores values as signed integers.
9963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // To represent the entire range, we need to store as a 64-bit
9973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // int and discard the high 32 bits.
9986ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ sub(Operand(esp), Immediate(2 * kPointerSize));
9993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fistp_d(Operand(esp, 0));
10006ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ pop(ecx);
10016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      __ add(Operand(esp), Immediate(kPointerSize));
10023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
10036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    // ecx: untagged integer value
10043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    switch (array_type) {
10053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalByteArray:
10063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedByteArray:
10076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
10083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalShortArray:
10103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedShortArray:
10116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
10123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalIntArray:
10143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedIntArray: {
10153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // We also need to explicitly check for +/-Infinity. These are
10163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // converted to MIN_INT, but we need to be careful not to
10173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // confuse with legal uses of MIN_INT.
10183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        Label not_infinity;
10193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // This test would apparently detect both NaN and Infinity,
10203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // but we've already checked for NaN using the FPU hardware
10213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // above.
10226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
10236ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ and_(edx, 0x7FF0);
10246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ cmp(edx, 0x7FF0);
10253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ j(not_equal, &not_infinity);
10266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(ecx, 0);
10273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ bind(&not_infinity);
10286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(Operand(edi, ebx, times_4, 0), ecx);
10293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
10313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      default:
10323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        UNREACHABLE();
10333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
10356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ ret(0);  // Return original value.
10363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&is_nan);
10383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ffree();
10393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fincstp();
10403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    switch (array_type) {
10413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalByteArray:
10423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedByteArray:
10436ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_b(Operand(edi, ebx, times_1, 0), 0);
10443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalShortArray:
10463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedShortArray:
10476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ xor_(ecx, Operand(ecx));
10486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
10493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalIntArray:
10513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedIntArray:
10526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block        __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
10533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      default:
10553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        UNREACHABLE();
10563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
10573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
10586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block    __ ret(0);  // Return the original value.
10593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
10603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
10623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&slow);
1063402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeSetProperty(masm);
10643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
10653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
10663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
1067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallIC_Miss(Arguments args);
1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1072e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1073e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1074e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1075e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1076e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label number, non_number, non_string, boolean, probe, miss;
1079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags =
1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the stub cache probing failed, the receiver might be a value.
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // For value objects, we use the map of the prototype objects for
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the corresponding JSValue for the cache and that is what we need
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to probe.
1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for number.
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &number, not_taken);
1096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &non_number, taken);
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&number);
1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::NUMBER_FUNCTION_INDEX, edx);
1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
1102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for string.
1104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_number);
1105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, FIRST_NONSTRING_TYPE);
1106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &non_string, taken);
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::STRING_FUNCTION_INDEX, edx);
1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for boolean.
1112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_string);
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::true_value());
1114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &boolean, not_taken);
1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::false_value());
1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, taken);
1117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&boolean);
1118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache for the value object.
1122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&probe);
1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1127e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm, argc);
1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateNormalHelper(MacroAssembler* masm,
1132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 int argc,
1133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 bool is_global_object,
1134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Label* miss) {
1135e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
1136e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1137e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- edx                 : receiver
1138e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1139e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1140e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1141e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1142e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
1143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1144e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Search dictionary - put result in register edi.
1145e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ mov(edi, edx);
1146402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY);
1147e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1148e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the result is not a smi.
1149e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ test(edi, Immediate(kSmiTagMask));
1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1152e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the value is a JavaScript function, fetching its map into eax.
1153e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss, not_taken);
1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1156e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Patch the receiver on stack with the global proxy if necessary.
1157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_global_object) {
1158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1170e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1171e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1172e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1173e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1174e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss, global_object, non_global_object;
1177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
1184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver is a valid JS object.
1186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
1188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, FIRST_JS_OBJECT_TYPE);
1189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &miss, not_taken);
1190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If this assert fails, we have to check upper bound too.
1192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for access to global object.
1195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global_object);
1197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
1198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &non_global_object);
1199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Accessing global object: Load and invoke.
1201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global_object);
1202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the global object does not require access checks.
1203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
1206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateNormalHelper(masm, argc, true, &miss);
1207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Accessing non-global object: Check for access to global proxy.
1209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label global_proxy, invoke;
1210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_global_object);
1211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
1212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global_proxy, not_taken);
1213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the non-global, non-global-proxy object does not
1214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // require access checks.
1215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
1218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
1219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateNormalHelper(masm, argc, false, &miss);
1220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Global object proxy access: Check access rights.
1222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global_proxy);
1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CheckAccessGlobalProxy(edx, eax, &miss);
1224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&invoke);
1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1228e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm, argc);
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1232e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1234e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1235e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1236e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1237e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1238e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter an internal frame.
1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterInternalFrame();
1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the receiver and the name of the function.
1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(edx);
1249e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(ecx);
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the entry.
1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CEntryStub stub(1);
1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Immediate(2));
1254e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ mov(ebx, Immediate(ExternalReference(IC_Utility(kCallIC_Miss))));
1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallStub(&stub);
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move result to edi and exit the internal frame.
1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edi, eax);
1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveInternalFrame();
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the receiver is a global object of some sort.
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label invoke, global;
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &invoke, not_taken);
1266e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1267e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1268e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global);
1270e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &invoke);
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the receiver on the stack.
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global);
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadIC_Miss(Arguments args);
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1290402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1302402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateNormal(MacroAssembler* masm) {
1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1308402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss, probe, global;
1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
1316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
1317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver is a valid JS object.
1319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, FIRST_JS_OBJECT_TYPE);
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(less, &miss, not_taken);
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If this assert fails, we have to check upper bound too.
1325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for access to global object (unlikely).
1328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
1329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global, not_taken);
1330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for non-global object that requires access check.
1332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &miss, not_taken);
1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Search the dictionary placing the result in eax.
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&probe);
1338402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateDictionaryLoad(masm,
1339402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         &miss,
1340402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         eax,
1341402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ecx,
1342402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         edx,
1343402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         edi,
1344402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ebx,
1345402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         CHECK_DICTIONARY);
1346402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, edi);
1347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Global object access: Check access rights.
1350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global);
1351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CheckAccessGlobalProxy(eax, edx, &miss);
1352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
1353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Restore receiver from stack and jump to runtime.
1355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1356402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMiss(MacroAssembler* masm) {
1361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1362402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // receiver
1369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);  // name
1370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
13736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
13746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
1375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// One byte opcode for test eax,0xXXXXXXXX.
1379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const byte kTestEaxByte = 0xA9;
1380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::ClearInlinedVersion(Address address) {
1383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Reset the map check of the inlined inobject property load (if
1384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // present) to guarantee failure by holding an invalid map (the null
1385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // value).  The offset can be patched to anything.
1386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
1387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::ClearInlinedVersion(Address address) {
1391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Insert null as the map to check for to make sure the map check fails
1392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sending control flow to the IC instead of the inlined version.
1393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedLoad(address, Heap::null_value());
1394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::ClearInlinedVersion(Address address) {
1398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Insert null as the elements map to check for.  This will make
1399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sure that the elements fast-case map check fails so that control
1400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // flows to the IC instead of the inlined version.
1401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedStore(address, Heap::null_value());
1402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::RestoreInlinedVersion(Address address) {
1406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore the fast-case elements map check so that the inlined
1407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // version can be used again.
1408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedStore(address, Heap::fixed_array_map());
1409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The address of the instruction following the call.
1414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the instruction following the call is not a test eax, nothing
1417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // was inlined.
1418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (*test_instruction_address != kTestEaxByte) return false;
1419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The delta to the start of the map check instruction.
1422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The map address is the last 4 bytes of the 7-byte
1425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand-immediate compare instruction, so we add 3 to get the
1426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The offset is in the last 4 bytes of a six byte
1431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // memory-to-register move instruction, so we add 2 to get the
1432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address offset_address =
1434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool PatchInlinedMapCheck(Address address, Object* map) {
1441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The keyed load has a fast inlined case if the IC call instruction
1444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is immediately followed by a test instruction.
1445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (*test_instruction_address != kTestEaxByte) return false;
1446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch the offset from the test instruction to the map cmp
1448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction.  This offset is stored in the last 4 bytes of the 5
1449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // byte test instruction.
1450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the map address.  The map address is in the last 4 bytes
1453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the 7-byte operand-immediate compare instruction, so we add 3
1454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the offset to get the map address.
1455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the map check.
1457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadIC_Miss(Arguments args);
1474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1478402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1479402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1480a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1481a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1482a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1483402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ebx);
1484402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1485402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // name
1486402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ebx);  // return address
1487402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1488402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
14896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
14906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
1491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1494402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1496402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1497402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1502402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // name
1504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
15076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
1508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StoreIC::GenerateMegamorphic(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  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
15254515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  GenerateMiss(masm);
1526a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1527a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1528a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15294515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid StoreIC::GenerateMiss(MacroAssembler* masm) {
1530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
15334515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
15384515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(edx);
1539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
1540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);
1541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);
1542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
15446ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
15456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 3, 1);
15466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block}
15476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15496ded16be15dd865a9b21ea304d5273c8be299c87Steve Blockvoid StoreIC::GenerateArrayLength(MacroAssembler* masm) {
15506ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // ----------- S t a t e -------------
15516ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- eax    : value
15526ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : name
15536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
15546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- esp[0] : return address
15556ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // -----------------------------------
15566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
15576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // This accepts as a receiver anything JSObject::SetElementsLength accepts
15586ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // (currently anything except for external and pixel arrays which means
15596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // anything with elements of FixedArray type.), but currently is restricted
15606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // to JSArray.
15616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Value must be a number, but only smis are accepted as the most common case.
15626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Label miss;
15646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register receiver = edx;
15666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register value = eax;
15676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Register scratch = ebx;
15686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the receiver isn't a smi.
15706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(receiver, Immediate(kSmiTagMask));
15716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(zero, &miss, not_taken);
15726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that the object is a JS array.
15746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
15756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &miss, not_taken);
15766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that elements are FixedArray.
15786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
15796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
15806ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_equal, &miss, not_taken);
15816ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15826ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Check that value is a smi.
15836ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ test(value, Immediate(kSmiTagMask));
15846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ j(not_zero, &miss, not_taken);
15856ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Prepare tail call to StoreIC_ArrayLength.
15876ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(scratch);
15886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(receiver);
15896ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(value);
15906ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(scratch);  // return address
15916ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15926ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
15936ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 2, 1);
15946ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15956ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ bind(&miss);
15966ded16be15dd865a9b21ea304d5273c8be299c87Steve Block
15976ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  GenerateMiss(masm);
1598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedStoreIC_Miss(Arguments args);
1603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1604402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
16076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
16086ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
1609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(ebx);
16136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
1614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
16156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(eax);
16166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(ebx);
1617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
16196ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
1620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1623402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
16266ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- ecx    : key
16276ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //  -- edx    : receiver
1628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
16316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ pop(ebx);
16326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(edx);
1633402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);
16346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(eax);
16356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ push(ebx);
1636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
16386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
16396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  __ TailCallExternalReference(ref, 3, 1);
1640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
1643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
1646