ic-ia32.cc revision 402d937239b0e2fd11bf2f4fe972ad78aa9fd481
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  // Test the has_named_interceptor bit in the map.
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Jump to miss if the interceptor bit is set.
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, miss_label, not_taken);
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Bail out if we have a JS global proxy object.
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, miss_label, not_taken);
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Possible work-around for http://crbug.com/16276.
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, miss_label, not_taken);
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, miss_label, not_taken);
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load properties array.
95402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
96e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
97e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the properties array is a dictionary.
98e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if (check_dictionary == CHECK_DICTIONARY) {
99e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
100e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke           Immediate(Factory::hash_table_map()));
101e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    __ j(not_equal, miss_label);
102e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  }
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the capacity mask.
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kCapacityOffset =
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kCapacityIndex * kPointerSize;
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r2, FieldOperand(r0, kCapacityOffset));
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ shr(r2, kSmiTagSize);  // convert smi to int
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ dec(r2);
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Generate an unrolled loop that performs a few probes before
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // giving up. Measurements done on Gmail indicate that 2 probes
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // cover ~93% of loads from dictionaries.
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const int kProbes = 4;
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kElementsStartOffset =
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kHeaderSize +
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      StringDictionary::kElementsStartIndex * kPointerSize;
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for (int i = 0; i < kProbes; i++) {
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Compute the masked index: (hash + i + i * i) & mask.
121d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ shr(r1, String::kHashShift);
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i > 0) {
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ and_(r1, Operand(r2));
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Scale the index by multiplying by the entry size.
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ASSERT(StringDictionary::kEntrySize == 3);
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ lea(r1, Operand(r1, r1, times_2, 0));  // r1 = r1 * 3
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    // Check if the key is identical to the name.
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ cmp(name,
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (i != kProbes - 1) {
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(equal, &done, taken);
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    } else {
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      __ j(not_equal, miss_label, not_taken);
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the value is a normal property.
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&done);
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, miss_label, not_taken);
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the value at the masked, scaled index.
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const int kValueOffset = kElementsStartOffset + kPointerSize;
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// The offset from the inlined patch site to the start of the
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// inlined load instruction.  It is 7 bytes (test eax, imm) plus
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 6 bytes (jne slow_label).
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst int LoadIC::kOffsetToLoadInstruction = 13;
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateArrayLength(MacroAssembler* masm) {
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
163402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateStringLength(MacroAssembler* masm) {
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
177402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
191402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss;
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
205402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
206402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
209e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label slow, check_string, index_int, index_string;
210e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label check_pixel_array, probe_dictionary;
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
213402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map of the receiver.
217402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
218d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke
219d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  // Check bit field.
220402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
221d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  __ test(ebx, Immediate(kSlowCaseBitFieldMask));
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object EXCEPT JS Value type.
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In the case that the object is a value-wrapper object,
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we enter the runtime system to make sure that indexing
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // into string objects work as intended.
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
228402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
229402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(below, &slow, not_taken);
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &check_string, not_taken);
233402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, eax);
234402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiUntag(ebx);
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the elements array of the object.
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&index_int);
237402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is in fast mode (not dictionary).
239402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true);
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key (index) is within bounds.
241402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the load.
244402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(ecx, ebx, times_4, FixedArray::kHeaderSize));
245402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(Operand(ecx), Immediate(Factory::the_hole_value()));
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // In case the loaded value is the_hole we have to consult GetProperty
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to ensure the prototype chain is searched.
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &slow);
249402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, ecx);
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
254402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check whether the elements is a pixel array.
255402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
256402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: untagged index
257402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
258402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx: elements
259402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CheckMap(ecx, Factory::pixel_array_map(), &slow, true);
260402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
262402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
263402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
264402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiTag(eax);
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
268402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Slow case: jump to runtime.
269402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
270402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
272402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_string);
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The key is not a smi.
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Is it a string?
277402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver
278402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key
279402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Is the string an array index, with cached numeric value?
282d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(String::kIsArrayIndexMask));
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &index_string, not_taken);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
286e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Is the string a symbol?
287402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset));
288e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ASSERT(kSymbolTag != 0);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(kIsSymbolMask));
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
291e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
292e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // If the receiver is a fast-case object, check the keyed lookup
293402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // cache. Otherwise probe the dictionary.
294402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
295e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
296e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke         Immediate(Factory::hash_table_map()));
297e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(equal, &probe_dictionary);
298e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
299e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the map of the receiver, compute the keyed lookup cache hash
300e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // based on 32 bits of the map pointer and the string hash.
301402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
302402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, ebx);
303402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(ecx, KeyedLookupCache::kMapHashShift);
304402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
305402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(edi, String::kHashShift);
306402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ xor_(ecx, Operand(edi));
307402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(ecx, KeyedLookupCache::kCapacityMask);
308e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
309e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load the key (consisting of map and symbol) from the cache and
310e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // check for match.
311e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_keys
312e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_keys();
313402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi, ecx);
314e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ shl(edi, kPointerSizeLog2 + 1);
315e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
316e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
317e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ add(Operand(edi), Immediate(kPointerSize));
318402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
319e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &slow);
320e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
321e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Get field offset and check that it is an in-object property.
322402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx     : receiver
323402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx     : receiver's map
324402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax     : key
325402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx     : lookup cache index
326e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  ExternalReference cache_field_offsets
327e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      = ExternalReference::keyed_lookup_cache_field_offsets();
328402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(edi,
329402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu         Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
330402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
331402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(edi, Operand(ecx));
332e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(above_equal, &slow);
333e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
334e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Load in-object property.
335402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ sub(edi, Operand(ecx));
336402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
337402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ add(ecx, Operand(edi));
338402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
339e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ ret(0);
340e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
341e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Do a quick inline probe of the receiver's dictionary, if it
342e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // exists.
343e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&probe_dictionary);
344e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateDictionaryLoad(masm,
345e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         &slow,
346e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         edx,
347e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         eax,
348402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ebx,
349402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ecx,
350402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         edi,
351e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke                         DICTIONARY_CHECK_DONE);
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Operand(ecx));
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
355e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
356d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // If the hash field contains an array index pick it out. The assert checks
357d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // that the constants for the maximum number of digits for an array index
358d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // cached in the hash field and the number of bits reserved for it does not
359d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // conflict.
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
361d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block         (1 << String::kArrayIndexValueBits));
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&index_string);
363402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(ebx, String::kArrayIndexHashMask);
364402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ shr(ebx, String::kHashShift);
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&index_int);
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
369e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid KeyedLoadIC::GenerateString(MacroAssembler* masm) {
370e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
371402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
372402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
373e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0] : return address
374e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
375e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  Label miss, index_ok;
376e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
377e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Pop return address.
378e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Performing the load early is better in the common case.
379402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ebx);
380e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
381402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
382e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, &miss);
383402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
384e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
385e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ test(ecx, Immediate(kIsNotStringMask));
386e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_zero, &miss);
387e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
388e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check if key is a smi or a heap number.
389402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(eax, Immediate(kSmiTagMask));
390e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(zero, &index_ok);
391402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
392e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ecx, Factory::heap_number_map());
393e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ j(not_equal, &miss);
394e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
395e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&index_ok);
396402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Push receiver and key on the stack, and make a tail call.
397402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
398402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // key
399402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ebx);  // return address
400e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ InvokeBuiltin(Builtins::STRING_CHAR_AT, JUMP_FUNCTION);
401e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
402e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ bind(&miss);
403402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ebx);
404e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm);
405e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke}
406e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
407e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
4083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
4093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                        ExternalArrayType array_type) {
4103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ----------- S t a t e -------------
411402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
412402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
4133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[0] : return address
4143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // -----------------------------------
4153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label slow, failed_allocation;
4163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
4173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object isn't a smi.
418402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
4193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &slow, not_taken);
4203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
4213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the key is a smi.
4223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(eax, Immediate(kSmiTagMask));
4233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow, not_taken);
4243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
4253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the map of the receiver.
426402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
4273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the receiver does not require access checks.  We need
4283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // to check this explicitly since this generic stub does not perform
4293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // map checks.
430402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
4313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
4323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow, not_taken);
4333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
434402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
4353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow, not_taken);
4363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
4373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the elements array is the appropriate type of
4383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ExternalArray.
439402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
4403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
441402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
4423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(map));
4433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow, not_taken);
4443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
445402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // eax: key, known to be a smi.
446402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // edx: receiver, known to be a JSObject.
447402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: elements object, known to be an external array.
4483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the index is in range.
449402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, eax);
450402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ SmiUntag(ecx);  // Untag the index.
451402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
4523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Unsigned comparison catches both negative and too-large values.
4533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(above_equal, &slow);
4543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
455402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
456402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ebx: base pointer of external storage
4573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (array_type) {
4583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalByteArray:
459402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
4603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedByteArray:
462402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
4633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalShortArray:
465402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
4663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedShortArray:
468402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
4693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalIntArray:
4713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedIntArray:
472402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ mov(ecx, Operand(ebx, ecx, times_4, 0));
4733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalFloatArray:
475402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ fld_s(Operand(ebx, ecx, times_4, 0));
4763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    default:
4783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
4793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
4803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
4813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
4823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // For integer array types:
483402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ecx: value
4843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // For floating-point array type:
4853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // FP(0): value
4863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
4873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (array_type == kExternalIntArray ||
4883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      array_type == kExternalUnsignedIntArray) {
4893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // For the Int and UnsignedInt array types, we need to see whether
4903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // the value can be represented in a Smi. If not, we need to convert
4913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // it to a HeapNumber.
4923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label box_int;
4933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type == kExternalIntArray) {
494402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ cmp(ecx, 0xC0000000);
495402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ j(sign, &box_int);
4963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
4973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ASSERT_EQ(array_type, kExternalUnsignedIntArray);
4983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // The test is different for unsigned int values. Since we need
499402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      // the value to be in the range of a positive smi, we can't
5003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // handle either of the top two bits being set in the value.
501402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ test(ecx, Immediate(0xC0000000));
5023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ j(not_zero, &box_int);
5033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
5043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
505402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
506402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiTag(eax);
5073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
5083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&box_int);
5103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Allocate a HeapNumber for the int and perform int-to-double
5123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // conversion.
5133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type == kExternalIntArray) {
514402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ push(ecx);
5153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_s(Operand(esp, 0));
516402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
5173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
5183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      ASSERT(array_type == kExternalUnsignedIntArray);
5193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Need to zero-extend the value.
5203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // There's no fild variant for unsigned values, so zero-extend
5213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // to a 64-bit int manually.
5223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(Immediate(0));
523402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ push(ecx);
5243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_d(Operand(esp, 0));
525402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
526402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu      __ pop(ecx);
5273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
5283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // FP(0): value
529402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
5303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Set the value.
531402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
5323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
5333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
5343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else if (array_type == kExternalFloatArray) {
5353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // For the floating-point array type, we need to always allocate a
5363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // HeapNumber.
537402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
5383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Set the value.
539402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
5403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
5413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
5423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
543402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ mov(eax, ecx);
544402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu    __ SmiTag(eax);
5453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
5463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
5473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
5483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // If we fail allocation of the HeapNumber, we still have a value on
5493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // top of the FPU stack. Remove it.
5503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&failed_allocation);
5513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ ffree();
5523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fincstp();
5533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Fall through to slow case.
5543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
555402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Slow case: Load key and receiver from stack and jump to runtime.
5563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&slow);
5573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
558402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeGetProperty(masm);
559402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu}
560402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
561402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
562402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
563402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // ----------- S t a t e -------------
564402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
565402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
566402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- esp[0] : return address
567402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // -----------------------------------
568402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  Label slow;
569402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
570402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the receiver isn't a smi.
571402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(edx, Immediate(kSmiTagMask));
572402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(zero, &slow, not_taken);
573402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
574402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that the key is a smi.
575402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ test(eax, Immediate(kSmiTagMask));
576402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
577402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
578402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Get the map of the receiver.
579402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
580402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
581402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Check that it has indexed interceptor and access checks
582402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // are not enabled for this object.
583402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
584402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
585402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
586402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ j(not_zero, &slow, not_taken);
587402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
588402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Everything is fine, call runtime.
589402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ecx);
590402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
591402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // key
592402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);  // return address
593402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
594402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
595402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(
596402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu        IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
597402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
598402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ bind(&slow);
599402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
6003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
6013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
6023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[4] : key
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[8] : receiver
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label slow, fast, array, extra, check_pixel_array;
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver from the stack.
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, 2 * kPointerSize));  // 2 ~ return address, key
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object isn't a smi.
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &slow, not_taken);
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the map from the receiver.
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver does not require access checks.  We need
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to do this because this generic stub does not perform map checks.
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the key from the stack.
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the key is a smi.
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(kSmiTagMask));
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow, not_taken);
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the instance type from the map of the receiver.
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the object is a JS array or not.
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ecx, JS_ARRAY_TYPE);
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &array);
634a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is some kind of JS object.
635a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
636a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(less, &slow, not_taken);
637a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
638a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Object case: Check key against length in the elements array.
639a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
640a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSObject
641a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: index (as a smi)
642a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
643a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the object is in fast mode (not dictionary).
644a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
645a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Factory::fixed_array_map()));
646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &check_pixel_array, not_taken);
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Untag the key (for checking against untagged length in the fixed array).
648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(ebx));
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sar(edx, kSmiTagSize);  // untag the index and use it for the comparison
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, FieldOperand(ecx, Array::kLengthOffset));
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ecx: FixedArray
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: index (as a smi)
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &fast, taken);
655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&slow);
658402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeSetProperty(masm);
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check whether the elements is a pixel array.
661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ecx: elements array
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: index (as a smi)
664a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&check_pixel_array);
665a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
666a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Factory::pixel_array_map()));
667a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow);
668a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the value is a smi. If a conversion is needed call into the
669a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // runtime to convert and clamp.
670a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &slow);
672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sar(ebx, kSmiTagSize);  // Untag the index.
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow);
675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, eax);  // Save the value.
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sar(eax, kSmiTagSize);  // Untag the value.
677a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  {  // Clamp the value to [0..255].
6783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label done;
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ test(eax, Immediate(0xFFFFFF00));
680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ j(zero, &done);
6813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ setcc(negative, eax);  // 1 if negative, 0 if positive.
6823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ dec_b(eax);  // 0 if negative, 255 if positive.
683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ bind(&done);
684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
685a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ecx, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
686a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
687a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, edx);  // Return the original value.
688a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
689a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
690a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Extra capacity case: Check if there is extra capacity to
691a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // perform the store and update the length. Used for adding one
692a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // element to the array by writing to array[array.length].
693a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&extra);
694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSArray
696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ecx: FixedArray
697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: index (as a smi)
698a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // flags: compare (ebx, edx.length())
699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &slow, not_taken);  // do not leave holes in the array
700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sar(ebx, kSmiTagSize);  // untag
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, FieldOperand(ecx, Array::kLengthOffset));
702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &slow, not_taken);
703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore tag and increment.
704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ lea(ebx, Operand(ebx, times_2, 1 << kSmiTagSize));
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(FieldOperand(edx, JSArray::kLengthOffset), ebx);
706a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ sub(Operand(ebx), Immediate(1 << kSmiTagSize));  // decrement ebx again
707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&fast);
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Array case: Get the length and the elements array from the JS
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // array. Check that the array is in fast mode; if it is the
711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // length is always a smi.
712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&array);
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
714a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // edx: JSArray
715a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: index (as a smi)
716a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
717a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
718a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         Immediate(Factory::fixed_array_map()));
719a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &check_pixel_array);
720a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
721a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check the key against the length in the array, compute the
722a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // address to store into and fall through to fast case.
723a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, FieldOperand(edx, JSArray::kLengthOffset));
724a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &extra, not_taken);
725a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
726a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fast case: Do the store.
727a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&fast);
728a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // eax: value
729a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ecx: FixedArray
730a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ebx: index (as a smi)
731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(Operand(ecx, ebx, times_2, FixedArray::kHeaderSize - kHeapObjectTag),
732a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block         eax);
733a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Update write barrier for the elements array address.
734a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(eax));
735a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ RecordWrite(ecx, 0, edx, ebx);
736a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
737a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Blockvoid KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
7413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block                                         ExternalArrayType array_type) {
7423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ----------- S t a t e -------------
7433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- eax    : value
7443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[0] : return address
7453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[4] : key
7463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  //  -- esp[8] : receiver
7473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // -----------------------------------
7483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Label slow, check_heap_number;
7493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the receiver from the stack.
7513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(edx, Operand(esp, 2 * kPointerSize));
7523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object isn't a smi.
7533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(edx, Immediate(kSmiTagMask));
7543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(zero, &slow);
7553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the map from the receiver.
7563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
7573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the receiver does not require access checks.  We need
7583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // to do this because this generic stub does not perform map checks.
7593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
7603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
7613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow);
7623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the key from the stack.
7633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(ebx, Operand(esp, 1 * kPointerSize));  // 1 ~ return address
7643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the key is a smi.
7653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(ebx, Immediate(kSmiTagMask));
7663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_zero, &slow);
7673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Get the instance type from the map of the receiver.
7683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
7693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the object is a JS object.
7703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmp(ecx, JS_OBJECT_TYPE);
7713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
7723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the elements array is the appropriate type of
7743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ExternalArray.
7753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // eax: value
7763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // edx: JSObject
7773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: index (as a smi)
7783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
7793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  Handle<Map> map(Heap::MapForExternalArrayType(array_type));
7803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmp(FieldOperand(ecx, HeapObject::kMapOffset),
7813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(map));
7823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
7833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Check that the index is in range.
7853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ sar(ebx, kSmiTagSize);  // Untag the index.
7863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmp(ebx, FieldOperand(ecx, ExternalArray::kLengthOffset));
7873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Unsigned comparison catches both negative and too-large values.
7883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(above_equal, &slow);
7893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
7903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Handle both smis and HeapNumbers in the fast path. Go to the
7913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // runtime for all other kinds of values.
7923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // eax: value
7933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ecx: elements array
7943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: untagged index
7953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ test(eax, Immediate(kSmiTagMask));
7963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &check_heap_number);
7973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // smi case
7983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(edx, eax);  // Save the value.
7993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ sar(eax, kSmiTagSize);  // Untag the value.
8003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
8013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ecx: base pointer of external storage
8023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  switch (array_type) {
8033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalByteArray:
8043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedByteArray:
8053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
8063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalShortArray:
8083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedShortArray:
8093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
8103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalIntArray:
8123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalUnsignedIntArray:
8133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ mov(Operand(ecx, ebx, times_4, 0), eax);
8143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    case kExternalFloatArray:
8163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // Need to perform int-to-float conversion.
8173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(eax);
8183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fild_s(Operand(esp, 0));
8193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ pop(eax);
8203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fstp_s(Operand(ecx, ebx, times_4, 0));
8213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    default:
8233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      UNREACHABLE();
8243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      break;
8253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
8263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(eax, edx);  // Return the original value.
8273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ ret(0);
8283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&check_heap_number);
8303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
8313ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block         Immediate(Factory::heap_number_map()));
8323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ j(not_equal, &slow);
8333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // The WebGL specification leaves the behavior of storing NaN and
8353ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // +/-Infinity into integer arrays basically undefined. For more
8363ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // reproducible behavior, convert these to zero.
8373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
8383ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(edx, eax);  // Save the value.
8393ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ mov(ecx, FieldOperand(ecx, ExternalArray::kExternalPointerOffset));
8403ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ebx: untagged index
8413ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // ecx: base pointer of external storage
8423ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // top of FPU stack: value
8433ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  if (array_type == kExternalFloatArray) {
8443ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fstp_s(Operand(ecx, ebx, times_4, 0));
8453ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ mov(eax, edx);  // Return the original value.
8463ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
8473ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  } else {
8483ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Need to perform float-to-int conversion.
8493ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // Test the top of the FP stack for NaN.
8503ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    Label is_nan;
8513ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fucomi(0);
8523ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ j(parity_even, &is_nan);
8533ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
8543ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if (array_type != kExternalUnsignedIntArray) {
8553ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(eax);  // Make room on stack
8563ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fistp_s(Operand(esp, 0));
8573ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ pop(eax);
8583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    } else {
8593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // fistp stores values as signed integers.
8603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // To represent the entire range, we need to store as a 64-bit
8613ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      // int and discard the high 32 bits.
8623ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(eax);  // Make room on stack
8633ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ push(eax);  // Make room on stack
8643ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ fistp_d(Operand(esp, 0));
8653ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ pop(eax);
8663ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ mov(Operand(esp, 0), eax);
8673ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      __ pop(eax);
8683ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
8693ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    // eax: untagged integer value
8703ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    switch (array_type) {
8713ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalByteArray:
8723ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedByteArray:
8733ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov_b(Operand(ecx, ebx, times_1, 0), eax);
8743ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
8753ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalShortArray:
8763ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedShortArray:
8773ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
8783ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
8793ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalIntArray:
8803ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedIntArray: {
8813ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // We also need to explicitly check for +/-Infinity. These are
8823ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // converted to MIN_INT, but we need to be careful not to
8833ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // confuse with legal uses of MIN_INT.
8843ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        Label not_infinity;
8853ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // This test would apparently detect both NaN and Infinity,
8863ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // but we've already checked for NaN using the FPU hardware
8873ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        // above.
8883ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov_w(edi, FieldOperand(edx, HeapNumber::kValueOffset + 6));
8893ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ and_(edi, 0x7FF0);
8903ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ cmp(edi, 0x7FF0);
8913ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ j(not_equal, &not_infinity);
8923ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov(eax, 0);
8933ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ bind(&not_infinity);
8943ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov(Operand(ecx, ebx, times_4, 0), eax);
8953ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
8963ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      }
8973ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      default:
8983ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        UNREACHABLE();
8993ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
9003ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
9013ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ mov(eax, edx);  // Return the original value.
9023ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
9033ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9043ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ bind(&is_nan);
9053ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ffree();
9063ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ fincstp();
9073ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    switch (array_type) {
9083ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalByteArray:
9093ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedByteArray:
9103ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov_b(Operand(ecx, ebx, times_1, 0), 0);
9113ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
9123ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalShortArray:
9133ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedShortArray:
9143ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov(eax, 0);
9153ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov_w(Operand(ecx, ebx, times_2, 0), eax);
9163ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
9173ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalIntArray:
9183ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      case kExternalUnsignedIntArray:
9193ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        __ mov(Operand(ecx, ebx, times_4, 0), Immediate(0));
9203ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
9213ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      default:
9223ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        UNREACHABLE();
9233ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block        break;
9243ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    }
9253ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ mov(eax, edx);  // Return the original value.
9263ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    __ ret(0);
9273ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  }
9283ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9293ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  // Slow case: call runtime.
9303ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block  __ bind(&slow);
931402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateRuntimeSetProperty(masm);
9323ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block}
9333ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
9343ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block
935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* CallIC_Miss(Arguments args);
937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
940e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
941e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
942e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
943e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
944e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label number, non_number, non_string, boolean, probe, miss;
947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
950a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
951a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
952a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags =
953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the stub cache probing failed, the receiver might be a value.
957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // For value objects, we use the map of the prototype objects for
958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // the corresponding JSValue for the cache and that is what we need
959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to probe.
960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for number.
962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &number, not_taken);
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &non_number, taken);
966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&number);
967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::NUMBER_FUNCTION_INDEX, edx);
969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for string.
972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_number);
973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(ebx, FIRST_NONSTRING_TYPE);
974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(above_equal, &non_string, taken);
975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::STRING_FUNCTION_INDEX, edx);
977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for boolean.
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_string);
981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::true_value());
982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &boolean, not_taken);
983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, Factory::false_value());
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, taken);
985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&boolean);
986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCompiler::GenerateLoadGlobalFunctionPrototype(
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache for the value object.
990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&probe);
991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
995e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm, argc);
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void GenerateNormalHelper(MacroAssembler* masm,
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 int argc,
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 bool is_global_object,
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                 Label* miss) {
1003e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // ----------- S t a t e -------------
1004e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1005e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- edx                 : receiver
1006e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1007e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1008e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1009e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1010e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // -----------------------------------
1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1012e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Search dictionary - put result in register edi.
1013e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ mov(edi, edx);
1014402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY);
1015e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke
1016e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the result is not a smi.
1017e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ test(edi, Immediate(kSmiTagMask));
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, miss, not_taken);
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1020e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Check that the value is a JavaScript function, fetching its map into eax.
1021e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, miss, not_taken);
1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1024e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  // Patch the receiver on stack with the global proxy if necessary.
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (is_global_object) {
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1027a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1038e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1039e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1040e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1041e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1042e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss, global_object, non_global_object;
1045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
1052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver is a valid JS object.
1054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
1056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, FIRST_JS_OBJECT_TYPE);
1057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(below, &miss, not_taken);
1058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If this assert fails, we have to check upper bound too.
1060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for access to global object.
1063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
1064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global_object);
1065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
1066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &non_global_object);
1067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1068a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Accessing global object: Load and invoke.
1069a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global_object);
1070a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the global object does not require access checks.
1071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
1074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateNormalHelper(masm, argc, true, &miss);
1075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Accessing non-global object: Check for access to global proxy.
1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label global_proxy, invoke;
1078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&non_global_object);
1079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global_proxy, not_taken);
1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the non-global, non-global-proxy object does not
1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // require access checks.
1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &miss, not_taken);
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  GenerateNormalHelper(masm, argc, false, &miss);
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Global object proxy access: Check access rights.
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global_proxy);
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CheckAccessGlobalProxy(edx, eax, &miss);
1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&invoke);
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1096e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  GenerateMiss(masm, argc);
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1100e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkevoid CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1102e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ecx                 : name
1103e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[0]              : return address
1104e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc - n) * 4] : arg[n] (zero-based)
1105e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- ...
1106e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  //  -- esp[(argc + 1) * 4] : receiver
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Get the receiver of the function from the stack; 1 ~ return address.
1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Enter an internal frame.
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ EnterInternalFrame();
1114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Push the receiver and the name of the function.
1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(edx);
1117e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ push(ecx);
1118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Call the entry.
1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CEntryStub stub(1);
1121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(eax, Immediate(2));
1122e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ mov(ebx, Immediate(ExternalReference(IC_Utility(kCallIC_Miss))));
1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CallStub(&stub);
1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Move result to edi and exit the internal frame.
1126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edi, eax);
1127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ LeaveInternalFrame();
1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check if the receiver is a global object of some sort.
1130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label invoke, global;
1131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));  // receiver
1132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(edx, Immediate(kSmiTagMask));
1133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &invoke, not_taken);
1134e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1135e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1136e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
1137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global);
1138e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
1139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_equal, &invoke);
1140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the receiver on the stack.
1142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global);
1143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Invoke the function.
1147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ParameterCount actual(argc);
1148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&invoke);
1149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* LoadIC_Miss(Arguments args);
1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1158402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Probe the stub cache.
1164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
1170402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateNormal(MacroAssembler* masm) {
1175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1176402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Label miss, probe, global;
1181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver isn't a smi.
1183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(eax, Immediate(kSmiTagMask));
1184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(zero, &miss, not_taken);
1185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that the receiver is a valid JS object.
1187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, FIRST_JS_OBJECT_TYPE);
1190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(less, &miss, not_taken);
1191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If this assert fails, we have to check upper bound too.
1193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for access to global object (unlikely).
1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
1197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(equal, &global, not_taken);
1198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check for non-global object that requires access check.
1200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ j(not_zero, &miss, not_taken);
1203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Search the dictionary placing the result in eax.
1205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&probe);
1206402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateDictionaryLoad(masm,
1207402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         &miss,
1208402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         eax,
1209402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ecx,
1210402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         edx,
1211402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         edi,
1212402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         ebx,
1213402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu                         CHECK_DICTIONARY);
1214402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ mov(eax, edi);
1215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ ret(0);
1216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Global object access: Check access rights.
1218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&global);
1219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ CheckAccessGlobalProxy(eax, edx, &miss);
1220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ jmp(&probe);
1221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Restore receiver from stack and jump to runtime.
1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ bind(&miss);
1224402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  GenerateMiss(masm);
1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::GenerateMiss(MacroAssembler* masm) {
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1230402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : receiver
1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // receiver
1237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);  // name
1238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
1241402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(IC_Utility(kLoadIC_Miss)), 2, 1);
1242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// One byte opcode for test eax,0xXXXXXXXX.
1246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic const byte kTestEaxByte = 0xA9;
1247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid LoadIC::ClearInlinedVersion(Address address) {
1250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Reset the map check of the inlined inobject property load (if
1251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // present) to guarantee failure by holding an invalid map (the null
1252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // value).  The offset can be patched to anything.
1253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
1254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::ClearInlinedVersion(Address address) {
1258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Insert null as the map to check for to make sure the map check fails
1259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sending control flow to the IC instead of the inlined version.
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedLoad(address, Heap::null_value());
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::ClearInlinedVersion(Address address) {
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Insert null as the elements map to check for.  This will make
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sure that the elements fast-case map check fails so that control
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // flows to the IC instead of the inlined version.
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedStore(address, Heap::null_value());
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedStoreIC::RestoreInlinedVersion(Address address) {
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Restore the fast-case elements map check so that the inlined
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // version can be used again.
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  PatchInlinedStore(address, Heap::fixed_array_map());
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The address of the instruction following the call.
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // If the instruction following the call is not a test eax, nothing
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // was inlined.
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (*test_instruction_address != kTestEaxByte) return false;
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The delta to the start of the map check instruction.
1289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The map address is the last 4 bytes of the 7-byte
1292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // operand-immediate compare instruction, so we add 3 to get the
1293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The offset is in the last 4 bytes of a six byte
1298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // memory-to-register move instruction, so we add 2 to get the
1299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // offset to the last 4 bytes.
1300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address offset_address =
1301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic bool PatchInlinedMapCheck(Address address, Object* map) {
1308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address test_instruction_address =
1309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      address + Assembler::kCallTargetAddressOffset;
1310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The keyed load has a fast inlined case if the IC call instruction
1311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // is immediately followed by a test instruction.
1312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (*test_instruction_address != kTestEaxByte) return false;
1313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Fetch the offset from the test instruction to the map cmp
1315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // instruction.  This offset is stored in the last 4 bytes of the 5
1316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // byte test instruction.
1317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address delta_address = test_instruction_address + 1;
1318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int delta = *reinterpret_cast<int*>(delta_address);
1319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compute the map address.  The map address is in the last 4 bytes
1320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // of the 7-byte operand-immediate compare instruction, so we add 3
1321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // to the offset to get the map address.
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address map_address = test_instruction_address + delta + 3;
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Patch the map check.
1324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(reinterpret_cast<Object**>(map_address)) = map;
1325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return true;
1326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return PatchInlinedMapCheck(address, map);
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedLoadIC_Miss(Arguments args);
1341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1345402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1346402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1350402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ebx);
1351402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1352402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(eax);  // name
1353402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ebx);  // return address
1354402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu
1355402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  // Perform tail call to the entry.
1356402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedLoadIC_Miss)), 2, 1);
1357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1360402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1362402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- eax    : key
1363402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  //  -- edx    : receiver
1364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
1368402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(edx);  // receiver
1369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);  // name
1370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);  // return address
1371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
1373402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(Runtime::kKeyedGetProperty), 2, 1);
1374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockvoid StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
13814515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         NOT_IN_LOOP,
1387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                         MONOMORPHIC);
1388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Cache miss: Jump to runtime.
13914515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  GenerateMiss(masm);
1392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13954515c472dc3e5ed2448a564600976759e569a0a8Leon Clarkevoid StoreIC::GenerateMiss(MacroAssembler* masm) {
1396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- ecx    : name
13994515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  //  -- edx    : receiver
1400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ebx);
14044515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ push(edx);
1405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
1406a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);
1407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ebx);
1408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Perform tail call to the entry.
14104515c472dc3e5ed2448a564600976759e569a0a8Leon Clarke  __ TailCallRuntime(ExternalReference(IC_Utility(kStoreIC_Miss)), 3, 1);
1411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Defined in ic.cc.
1415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockObject* KeyedStoreIC_Miss(Arguments args);
1416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1417402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[4] : key
1422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[8] : receiver
1423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ pop(ecx);
1426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(Operand(esp, 1 * kPointerSize));
1427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(Operand(esp, 1 * kPointerSize));
1428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);
1429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(ecx);
1430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
1432402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3, 1);
1433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1436402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescuvoid KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
1437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // ----------- S t a t e -------------
1438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- eax    : value
1439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[0] : return address
1440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[4] : key
1441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //  -- esp[8] : receiver
1442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // -----------------------------------
1443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1444402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ pop(ecx);
1445402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(Operand(esp, 1 * kPointerSize));
1446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(Operand(esp, 1 * kPointerSize));
1447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  __ push(eax);
1448402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ push(ecx);
1449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Do tail-call to runtime routine.
1451402d937239b0e2fd11bf2f4fe972ad78aa9fd481Andrei Popescu  __ TailCallRuntime(ExternalReference(IC_Utility(kKeyedStoreIC_Miss)), 3, 1);
1452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
1453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#undef __
1455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} }  // namespace v8::internal
1458