blob: bc7a33c6cc927c89598e4f5cd2eac9068368fda9 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "codegen-inl.h"
31#include "ic-inl.h"
32#include "runtime.h"
33#include "stub-cache.h"
Steve Blockd0582a62009-12-15 09:54:21 +000034#include "utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035
36namespace v8 {
37namespace internal {
38
39// ----------------------------------------------------------------------------
40// Static IC stub generators.
41//
42
43#define __ ACCESS_MASM(masm)
44
45
46// Helper function used to load a property from a dictionary backing storage.
47// This function may return false negatives, so miss_label
48// must always call a backup property load that is complete.
49// This function is safe to call if the receiver has fast properties,
50// or if name is not a symbol, and will jump to the miss_label in that case.
Leon Clarkee46be812010-01-19 14:06:41 +000051static void GenerateDictionaryLoad(MacroAssembler* masm,
52 Label* miss_label,
Andrei Popescu402d9372010-02-26 13:31:12 +000053 Register receiver,
54 Register name,
Leon Clarkee46be812010-01-19 14:06:41 +000055 Register r0,
56 Register r1,
57 Register r2,
Leon Clarkee46be812010-01-19 14:06:41 +000058 DictionaryCheck check_dictionary) {
Steve Blocka7e24c12009-10-30 11:49:00 +000059 // Register use:
60 //
Andrei Popescu402d9372010-02-26 13:31:12 +000061 // name - holds the name of the property and is unchanged.
62 // receiver - holds the receiver and is unchanged.
63 // Scratch registers:
Steve Blocka7e24c12009-10-30 11:49:00 +000064 // r0 - used to hold the property dictionary.
65 //
Andrei Popescu402d9372010-02-26 13:31:12 +000066 // r1 - used for the index into the property dictionary
Steve Blocka7e24c12009-10-30 11:49:00 +000067 // - holds the result on exit.
68 //
69 // r2 - used to hold the capacity of the property dictionary.
Steve Blocka7e24c12009-10-30 11:49:00 +000070
71 Label done;
72
73 // Check for the absence of an interceptor.
74 // Load the map into r0.
Andrei Popescu402d9372010-02-26 13:31:12 +000075 __ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +000076
Steve Block6ded16b2010-05-10 14:33:55 +010077 // Bail out if the receiver has a named interceptor.
78 __ test(FieldOperand(r0, Map::kBitFieldOffset),
79 Immediate(1 << Map::kHasNamedInterceptor));
Steve Blocka7e24c12009-10-30 11:49:00 +000080 __ j(not_zero, miss_label, not_taken);
81
82 // Bail out if we have a JS global proxy object.
83 __ movzx_b(r0, FieldOperand(r0, Map::kInstanceTypeOffset));
84 __ cmp(r0, JS_GLOBAL_PROXY_TYPE);
85 __ j(equal, miss_label, not_taken);
86
87 // Possible work-around for http://crbug.com/16276.
88 __ cmp(r0, JS_GLOBAL_OBJECT_TYPE);
89 __ j(equal, miss_label, not_taken);
90 __ cmp(r0, JS_BUILTINS_OBJECT_TYPE);
91 __ j(equal, miss_label, not_taken);
92
Leon Clarkee46be812010-01-19 14:06:41 +000093 // Load properties array.
Andrei Popescu402d9372010-02-26 13:31:12 +000094 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
Leon Clarkee46be812010-01-19 14:06:41 +000095
96 // Check that the properties array is a dictionary.
97 if (check_dictionary == CHECK_DICTIONARY) {
98 __ cmp(FieldOperand(r0, HeapObject::kMapOffset),
99 Immediate(Factory::hash_table_map()));
100 __ j(not_equal, miss_label);
101 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000102
103 // Compute the capacity mask.
104 const int kCapacityOffset =
105 StringDictionary::kHeaderSize +
106 StringDictionary::kCapacityIndex * kPointerSize;
107 __ mov(r2, FieldOperand(r0, kCapacityOffset));
108 __ shr(r2, kSmiTagSize); // convert smi to int
109 __ dec(r2);
110
111 // Generate an unrolled loop that performs a few probes before
112 // giving up. Measurements done on Gmail indicate that 2 probes
113 // cover ~93% of loads from dictionaries.
114 static const int kProbes = 4;
115 const int kElementsStartOffset =
116 StringDictionary::kHeaderSize +
117 StringDictionary::kElementsStartIndex * kPointerSize;
118 for (int i = 0; i < kProbes; i++) {
119 // Compute the masked index: (hash + i + i * i) & mask.
Steve Blockd0582a62009-12-15 09:54:21 +0000120 __ mov(r1, FieldOperand(name, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 __ shr(r1, String::kHashShift);
122 if (i > 0) {
123 __ add(Operand(r1), Immediate(StringDictionary::GetProbeOffset(i)));
124 }
125 __ and_(r1, Operand(r2));
126
127 // Scale the index by multiplying by the entry size.
128 ASSERT(StringDictionary::kEntrySize == 3);
129 __ lea(r1, Operand(r1, r1, times_2, 0)); // r1 = r1 * 3
130
131 // Check if the key is identical to the name.
132 __ cmp(name,
133 Operand(r0, r1, times_4, kElementsStartOffset - kHeapObjectTag));
134 if (i != kProbes - 1) {
135 __ j(equal, &done, taken);
136 } else {
137 __ j(not_equal, miss_label, not_taken);
138 }
139 }
140
141 // Check that the value is a normal property.
142 __ bind(&done);
143 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
144 __ test(Operand(r0, r1, times_4, kDetailsOffset - kHeapObjectTag),
145 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
146 __ j(not_zero, miss_label, not_taken);
147
148 // Get the value at the masked, scaled index.
149 const int kValueOffset = kElementsStartOffset + kPointerSize;
150 __ mov(r1, Operand(r0, r1, times_4, kValueOffset - kHeapObjectTag));
151}
152
153
Steve Block6ded16b2010-05-10 14:33:55 +0100154static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
155 Label* miss,
156 Register elements,
157 Register key,
158 Register r0,
159 Register r1,
160 Register r2) {
161 // Register use:
162 //
163 // elements - holds the slow-case elements of the receiver and is unchanged.
164 //
165 // key - holds the smi key on entry and is unchanged if a branch is
166 // performed to the miss label. If the load succeeds and we
167 // fall through, key holds the result on exit.
168 //
169 // Scratch registers:
170 //
171 // r0 - holds the untagged key on entry and holds the hash once computed.
172 //
173 // r1 - used to hold the capacity mask of the dictionary
174 //
175 // r2 - used for the index into the dictionary.
176 Label done;
177
178 // Compute the hash code from the untagged key. This must be kept in sync
179 // with ComputeIntegerHash in utils.h.
180 //
181 // hash = ~hash + (hash << 15);
182 __ mov(r1, r0);
183 __ not_(r0);
184 __ shl(r1, 15);
185 __ add(r0, Operand(r1));
186 // hash = hash ^ (hash >> 12);
187 __ mov(r1, r0);
188 __ shr(r1, 12);
189 __ xor_(r0, Operand(r1));
190 // hash = hash + (hash << 2);
191 __ lea(r0, Operand(r0, r0, times_4, 0));
192 // hash = hash ^ (hash >> 4);
193 __ mov(r1, r0);
194 __ shr(r1, 4);
195 __ xor_(r0, Operand(r1));
196 // hash = hash * 2057;
197 __ imul(r0, r0, 2057);
198 // hash = hash ^ (hash >> 16);
199 __ mov(r1, r0);
200 __ shr(r1, 16);
201 __ xor_(r0, Operand(r1));
202
203 // Compute capacity mask.
204 __ mov(r1, FieldOperand(elements, NumberDictionary::kCapacityOffset));
205 __ shr(r1, kSmiTagSize); // convert smi to int
206 __ dec(r1);
207
208 // Generate an unrolled loop that performs a few probes before giving up.
209 const int kProbes = 4;
210 for (int i = 0; i < kProbes; i++) {
211 // Use r2 for index calculations and keep the hash intact in r0.
212 __ mov(r2, r0);
213 // Compute the masked index: (hash + i + i * i) & mask.
214 if (i > 0) {
215 __ add(Operand(r2), Immediate(NumberDictionary::GetProbeOffset(i)));
216 }
217 __ and_(r2, Operand(r1));
218
219 // Scale the index by multiplying by the entry size.
220 ASSERT(NumberDictionary::kEntrySize == 3);
221 __ lea(r2, Operand(r2, r2, times_2, 0)); // r2 = r2 * 3
222
223 // Check if the key matches.
224 __ cmp(key, FieldOperand(elements,
225 r2,
226 times_pointer_size,
227 NumberDictionary::kElementsStartOffset));
228 if (i != (kProbes - 1)) {
229 __ j(equal, &done, taken);
230 } else {
231 __ j(not_equal, miss, not_taken);
232 }
233 }
234
235 __ bind(&done);
236 // Check that the value is a normal propety.
237 const int kDetailsOffset =
238 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
239 ASSERT_EQ(NORMAL, 0);
240 __ test(FieldOperand(elements, r2, times_pointer_size, kDetailsOffset),
241 Immediate(PropertyDetails::TypeField::mask() << kSmiTagSize));
242 __ j(not_zero, miss);
243
244 // Get the value at the masked, scaled index.
245 const int kValueOffset =
246 NumberDictionary::kElementsStartOffset + kPointerSize;
247 __ mov(key, FieldOperand(elements, r2, times_pointer_size, kValueOffset));
248}
249
250
Steve Blocka7e24c12009-10-30 11:49:00 +0000251// The offset from the inlined patch site to the start of the
252// inlined load instruction. It is 7 bytes (test eax, imm) plus
253// 6 bytes (jne slow_label).
254const int LoadIC::kOffsetToLoadInstruction = 13;
255
256
257void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
258 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000259 // -- eax : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000260 // -- ecx : name
261 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 Label miss;
264
Steve Blocka7e24c12009-10-30 11:49:00 +0000265 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
266 __ bind(&miss);
267 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
268}
269
270
271void LoadIC::GenerateStringLength(MacroAssembler* masm) {
272 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000273 // -- eax : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000274 // -- ecx : name
275 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000276 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 Label miss;
278
Andrei Popescu402d9372010-02-26 13:31:12 +0000279 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 __ bind(&miss);
281 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
282}
283
284
285void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
286 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000287 // -- eax : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 // -- ecx : name
289 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 Label miss;
292
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
294 __ bind(&miss);
295 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
296}
297
298
Steve Blocka7e24c12009-10-30 11:49:00 +0000299void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
300 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000301 // -- eax : key
302 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 // -----------------------------------
Leon Clarkee46be812010-01-19 14:06:41 +0000305 Label slow, check_string, index_int, index_string;
306 Label check_pixel_array, probe_dictionary;
Steve Block6ded16b2010-05-10 14:33:55 +0100307 Label check_number_dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +0000308
Steve Blocka7e24c12009-10-30 11:49:00 +0000309 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +0000310 __ test(edx, Immediate(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +0000311 __ j(zero, &slow, not_taken);
312
313 // Get the map of the receiver.
Andrei Popescu402d9372010-02-26 13:31:12 +0000314 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
Leon Clarked91b9f72010-01-27 17:25:45 +0000315
316 // Check bit field.
Andrei Popescu402d9372010-02-26 13:31:12 +0000317 __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
Leon Clarked91b9f72010-01-27 17:25:45 +0000318 __ test(ebx, Immediate(kSlowCaseBitFieldMask));
Steve Blocka7e24c12009-10-30 11:49:00 +0000319 __ j(not_zero, &slow, not_taken);
320 // Check that the object is some kind of JS object EXCEPT JS Value type.
321 // In the case that the object is a value-wrapper object,
322 // we enter the runtime system to make sure that indexing
323 // into string objects work as intended.
324 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
Andrei Popescu402d9372010-02-26 13:31:12 +0000325 __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
326 __ j(below, &slow, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000327 // Check that the key is a smi.
328 __ test(eax, Immediate(kSmiTagMask));
329 __ j(not_zero, &check_string, not_taken);
Andrei Popescu402d9372010-02-26 13:31:12 +0000330 __ mov(ebx, eax);
331 __ SmiUntag(ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000332 // Get the elements array of the object.
333 __ bind(&index_int);
Andrei Popescu402d9372010-02-26 13:31:12 +0000334 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000335 // Check that the object is in fast mode (not dictionary).
Andrei Popescu402d9372010-02-26 13:31:12 +0000336 __ CheckMap(ecx, Factory::fixed_array_map(), &check_pixel_array, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000337 // Check that the key (index) is within bounds.
Andrei Popescu402d9372010-02-26 13:31:12 +0000338 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000339 __ j(above_equal, &slow);
340 // Fast case: Do the load.
Andrei Popescu402d9372010-02-26 13:31:12 +0000341 __ mov(ecx, FieldOperand(ecx, ebx, times_4, FixedArray::kHeaderSize));
342 __ cmp(Operand(ecx), Immediate(Factory::the_hole_value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 // In case the loaded value is the_hole we have to consult GetProperty
344 // to ensure the prototype chain is searched.
345 __ j(equal, &slow);
Andrei Popescu402d9372010-02-26 13:31:12 +0000346 __ mov(eax, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1);
348 __ ret(0);
349
Steve Blocka7e24c12009-10-30 11:49:00 +0000350 __ bind(&check_pixel_array);
Andrei Popescu402d9372010-02-26 13:31:12 +0000351 // Check whether the elements is a pixel array.
352 // edx: receiver
353 // ebx: untagged index
354 // eax: key
355 // ecx: elements
Steve Block6ded16b2010-05-10 14:33:55 +0100356 __ CheckMap(ecx, Factory::pixel_array_map(), &check_number_dictionary, true);
Andrei Popescu402d9372010-02-26 13:31:12 +0000357 __ cmp(ebx, FieldOperand(ecx, PixelArray::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 __ j(above_equal, &slow);
Andrei Popescu402d9372010-02-26 13:31:12 +0000359 __ mov(eax, FieldOperand(ecx, PixelArray::kExternalPointerOffset));
360 __ movzx_b(eax, Operand(eax, ebx, times_1, 0));
361 __ SmiTag(eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000362 __ ret(0);
363
Steve Block6ded16b2010-05-10 14:33:55 +0100364 __ bind(&check_number_dictionary);
365 // Check whether the elements is a number dictionary.
366 // edx: receiver
367 // ebx: untagged index
368 // eax: key
369 // ecx: elements
370 __ CheckMap(ecx, Factory::hash_table_map(), &slow, true);
371 Label slow_pop_receiver;
372 // Push receiver on the stack to free up a register for the dictionary
373 // probing.
374 __ push(edx);
375 GenerateNumberDictionaryLoad(masm,
376 &slow_pop_receiver,
377 ecx,
378 eax,
379 ebx,
380 edx,
381 edi);
382 // Pop receiver before returning.
383 __ pop(edx);
384 __ ret(0);
385
386 __ bind(&slow_pop_receiver);
387 // Pop the receiver from the stack and jump to runtime.
388 __ pop(edx);
389
Steve Blocka7e24c12009-10-30 11:49:00 +0000390 __ bind(&slow);
Andrei Popescu402d9372010-02-26 13:31:12 +0000391 // Slow case: jump to runtime.
392 // edx: receiver
393 // eax: key
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000395 GenerateRuntimeGetProperty(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000396
397 __ bind(&check_string);
398 // The key is not a smi.
399 // Is it a string?
Andrei Popescu402d9372010-02-26 13:31:12 +0000400 // edx: receiver
401 // eax: key
402 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000403 __ j(above_equal, &slow);
404 // Is the string an array index, with cached numeric value?
Steve Blockd0582a62009-12-15 09:54:21 +0000405 __ mov(ebx, FieldOperand(eax, String::kHashFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 __ test(ebx, Immediate(String::kIsArrayIndexMask));
407 __ j(not_zero, &index_string, not_taken);
408
Leon Clarkee46be812010-01-19 14:06:41 +0000409 // Is the string a symbol?
Andrei Popescu402d9372010-02-26 13:31:12 +0000410 __ movzx_b(ebx, FieldOperand(ecx, Map::kInstanceTypeOffset));
Leon Clarkee46be812010-01-19 14:06:41 +0000411 ASSERT(kSymbolTag != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000412 __ test(ebx, Immediate(kIsSymbolMask));
413 __ j(zero, &slow, not_taken);
Leon Clarkee46be812010-01-19 14:06:41 +0000414
415 // If the receiver is a fast-case object, check the keyed lookup
Andrei Popescu402d9372010-02-26 13:31:12 +0000416 // cache. Otherwise probe the dictionary.
417 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
Leon Clarkee46be812010-01-19 14:06:41 +0000418 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
419 Immediate(Factory::hash_table_map()));
420 __ j(equal, &probe_dictionary);
421
422 // Load the map of the receiver, compute the keyed lookup cache hash
423 // based on 32 bits of the map pointer and the string hash.
Andrei Popescu402d9372010-02-26 13:31:12 +0000424 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
425 __ mov(ecx, ebx);
426 __ shr(ecx, KeyedLookupCache::kMapHashShift);
427 __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
428 __ shr(edi, String::kHashShift);
429 __ xor_(ecx, Operand(edi));
430 __ and_(ecx, KeyedLookupCache::kCapacityMask);
Leon Clarkee46be812010-01-19 14:06:41 +0000431
432 // Load the key (consisting of map and symbol) from the cache and
433 // check for match.
434 ExternalReference cache_keys
435 = ExternalReference::keyed_lookup_cache_keys();
Andrei Popescu402d9372010-02-26 13:31:12 +0000436 __ mov(edi, ecx);
Leon Clarkee46be812010-01-19 14:06:41 +0000437 __ shl(edi, kPointerSizeLog2 + 1);
438 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
439 __ j(not_equal, &slow);
440 __ add(Operand(edi), Immediate(kPointerSize));
Andrei Popescu402d9372010-02-26 13:31:12 +0000441 __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
Leon Clarkee46be812010-01-19 14:06:41 +0000442 __ j(not_equal, &slow);
443
444 // Get field offset and check that it is an in-object property.
Andrei Popescu402d9372010-02-26 13:31:12 +0000445 // edx : receiver
446 // ebx : receiver's map
447 // eax : key
448 // ecx : lookup cache index
Leon Clarkee46be812010-01-19 14:06:41 +0000449 ExternalReference cache_field_offsets
450 = ExternalReference::keyed_lookup_cache_field_offsets();
Andrei Popescu402d9372010-02-26 13:31:12 +0000451 __ mov(edi,
452 Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
453 __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
454 __ cmp(edi, Operand(ecx));
Leon Clarkee46be812010-01-19 14:06:41 +0000455 __ j(above_equal, &slow);
456
457 // Load in-object property.
Andrei Popescu402d9372010-02-26 13:31:12 +0000458 __ sub(edi, Operand(ecx));
459 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
460 __ add(ecx, Operand(edi));
461 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
Leon Clarkee46be812010-01-19 14:06:41 +0000462 __ ret(0);
463
464 // Do a quick inline probe of the receiver's dictionary, if it
465 // exists.
466 __ bind(&probe_dictionary);
467 GenerateDictionaryLoad(masm,
468 &slow,
Leon Clarkee46be812010-01-19 14:06:41 +0000469 edx,
470 eax,
Andrei Popescu402d9372010-02-26 13:31:12 +0000471 ebx,
472 ecx,
473 edi,
Leon Clarkee46be812010-01-19 14:06:41 +0000474 DICTIONARY_CHECK_DONE);
Steve Block6ded16b2010-05-10 14:33:55 +0100475 __ mov(eax, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000476 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
477 __ ret(0);
Leon Clarkee46be812010-01-19 14:06:41 +0000478
Steve Blockd0582a62009-12-15 09:54:21 +0000479 // If the hash field contains an array index pick it out. The assert checks
480 // that the constants for the maximum number of digits for an array index
481 // cached in the hash field and the number of bits reserved for it does not
482 // conflict.
Steve Blocka7e24c12009-10-30 11:49:00 +0000483 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
Steve Blockd0582a62009-12-15 09:54:21 +0000484 (1 << String::kArrayIndexValueBits));
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 __ bind(&index_string);
Andrei Popescu402d9372010-02-26 13:31:12 +0000486 __ and_(ebx, String::kArrayIndexHashMask);
487 __ shr(ebx, String::kHashShift);
Steve Blocka7e24c12009-10-30 11:49:00 +0000488 __ jmp(&index_int);
489}
490
491
Leon Clarkee46be812010-01-19 14:06:41 +0000492void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
493 // ----------- S t a t e -------------
Steve Block6ded16b2010-05-10 14:33:55 +0100494 // -- eax : key (index)
Andrei Popescu402d9372010-02-26 13:31:12 +0000495 // -- edx : receiver
Leon Clarkee46be812010-01-19 14:06:41 +0000496 // -- esp[0] : return address
Leon Clarkee46be812010-01-19 14:06:41 +0000497 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +0100498 Label miss;
499 Label index_not_smi;
500 Label index_out_of_range;
501 Label slow_char_code;
502 Label got_char_code;
Leon Clarkee46be812010-01-19 14:06:41 +0000503
Steve Block6ded16b2010-05-10 14:33:55 +0100504 Register receiver = edx;
505 Register index = eax;
506 Register code = ebx;
507 Register scratch = ecx;
Leon Clarkee46be812010-01-19 14:06:41 +0000508
Steve Block6ded16b2010-05-10 14:33:55 +0100509 StringHelper::GenerateFastCharCodeAt(masm,
510 receiver,
511 index,
512 scratch,
513 code,
514 &miss, // When not a string.
515 &index_not_smi,
516 &index_out_of_range,
517 &slow_char_code);
518 // If we didn't bail out, code register contains smi tagged char
519 // code.
520 __ bind(&got_char_code);
521 StringHelper::GenerateCharFromCode(masm, code, eax, JUMP_FUNCTION);
522#ifdef DEBUG
523 __ Abort("Unexpected fall-through from char from code tail call");
524#endif
Leon Clarkee46be812010-01-19 14:06:41 +0000525
Steve Block6ded16b2010-05-10 14:33:55 +0100526 // Check if key is a heap number.
527 __ bind(&index_not_smi);
528 __ CheckMap(index, Factory::heap_number_map(), &miss, true);
Leon Clarkee46be812010-01-19 14:06:41 +0000529
Steve Block6ded16b2010-05-10 14:33:55 +0100530 // Push receiver and key on the stack (now that we know they are a
531 // string and a number), and call runtime.
532 __ bind(&slow_char_code);
533 __ EnterInternalFrame();
534 __ push(receiver);
535 __ push(index);
536 __ CallRuntime(Runtime::kStringCharCodeAt, 2);
537 ASSERT(!code.is(eax));
538 __ mov(code, eax);
539 __ LeaveInternalFrame();
540
541 // Check if the runtime call returned NaN char code. If yes, return
542 // undefined. Otherwise, we can continue.
543 if (FLAG_debug_code) {
544 ASSERT(kSmiTag == 0);
545 __ test(code, Immediate(kSmiTagMask));
546 __ j(zero, &got_char_code);
547 __ mov(scratch, FieldOperand(code, HeapObject::kMapOffset));
548 __ cmp(scratch, Factory::heap_number_map());
549 __ Assert(equal, "StringCharCodeAt must return smi or heap number");
550 }
551 __ cmp(code, Factory::nan_value());
552 __ j(not_equal, &got_char_code);
553 __ bind(&index_out_of_range);
554 __ Set(eax, Immediate(Factory::undefined_value()));
555 __ ret(0);
Leon Clarkee46be812010-01-19 14:06:41 +0000556
557 __ bind(&miss);
Leon Clarkee46be812010-01-19 14:06:41 +0000558 GenerateMiss(masm);
559}
560
561
Steve Block3ce2e202009-11-05 08:53:23 +0000562void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
563 ExternalArrayType array_type) {
564 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000565 // -- eax : key
566 // -- edx : receiver
Steve Block3ce2e202009-11-05 08:53:23 +0000567 // -- esp[0] : return address
Steve Block3ce2e202009-11-05 08:53:23 +0000568 // -----------------------------------
569 Label slow, failed_allocation;
570
Steve Block3ce2e202009-11-05 08:53:23 +0000571 // Check that the object isn't a smi.
Andrei Popescu402d9372010-02-26 13:31:12 +0000572 __ test(edx, Immediate(kSmiTagMask));
Steve Block3ce2e202009-11-05 08:53:23 +0000573 __ j(zero, &slow, not_taken);
574
575 // Check that the key is a smi.
576 __ test(eax, Immediate(kSmiTagMask));
577 __ j(not_zero, &slow, not_taken);
578
579 // Get the map of the receiver.
Andrei Popescu402d9372010-02-26 13:31:12 +0000580 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000581 // Check that the receiver does not require access checks. We need
582 // to check this explicitly since this generic stub does not perform
583 // map checks.
Andrei Popescu402d9372010-02-26 13:31:12 +0000584 __ movzx_b(ebx, FieldOperand(ecx, Map::kBitFieldOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000585 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
586 __ j(not_zero, &slow, not_taken);
587
Andrei Popescu402d9372010-02-26 13:31:12 +0000588 __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
Steve Block3ce2e202009-11-05 08:53:23 +0000589 __ j(not_equal, &slow, not_taken);
590
591 // Check that the elements array is the appropriate type of
592 // ExternalArray.
Andrei Popescu402d9372010-02-26 13:31:12 +0000593 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000594 Handle<Map> map(Heap::MapForExternalArrayType(array_type));
Andrei Popescu402d9372010-02-26 13:31:12 +0000595 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
Steve Block3ce2e202009-11-05 08:53:23 +0000596 Immediate(map));
597 __ j(not_equal, &slow, not_taken);
598
Andrei Popescu402d9372010-02-26 13:31:12 +0000599 // eax: key, known to be a smi.
600 // edx: receiver, known to be a JSObject.
601 // ebx: elements object, known to be an external array.
Steve Block3ce2e202009-11-05 08:53:23 +0000602 // Check that the index is in range.
Andrei Popescu402d9372010-02-26 13:31:12 +0000603 __ mov(ecx, eax);
604 __ SmiUntag(ecx); // Untag the index.
605 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000606 // Unsigned comparison catches both negative and too-large values.
607 __ j(above_equal, &slow);
608
Andrei Popescu402d9372010-02-26 13:31:12 +0000609 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
610 // ebx: base pointer of external storage
Steve Block3ce2e202009-11-05 08:53:23 +0000611 switch (array_type) {
612 case kExternalByteArray:
Andrei Popescu402d9372010-02-26 13:31:12 +0000613 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000614 break;
615 case kExternalUnsignedByteArray:
Andrei Popescu402d9372010-02-26 13:31:12 +0000616 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000617 break;
618 case kExternalShortArray:
Andrei Popescu402d9372010-02-26 13:31:12 +0000619 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000620 break;
621 case kExternalUnsignedShortArray:
Andrei Popescu402d9372010-02-26 13:31:12 +0000622 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000623 break;
624 case kExternalIntArray:
625 case kExternalUnsignedIntArray:
Andrei Popescu402d9372010-02-26 13:31:12 +0000626 __ mov(ecx, Operand(ebx, ecx, times_4, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000627 break;
628 case kExternalFloatArray:
Andrei Popescu402d9372010-02-26 13:31:12 +0000629 __ fld_s(Operand(ebx, ecx, times_4, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000630 break;
631 default:
632 UNREACHABLE();
633 break;
634 }
635
636 // For integer array types:
Andrei Popescu402d9372010-02-26 13:31:12 +0000637 // ecx: value
Steve Block3ce2e202009-11-05 08:53:23 +0000638 // For floating-point array type:
639 // FP(0): value
640
641 if (array_type == kExternalIntArray ||
642 array_type == kExternalUnsignedIntArray) {
643 // For the Int and UnsignedInt array types, we need to see whether
644 // the value can be represented in a Smi. If not, we need to convert
645 // it to a HeapNumber.
646 Label box_int;
647 if (array_type == kExternalIntArray) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000648 __ cmp(ecx, 0xC0000000);
649 __ j(sign, &box_int);
Steve Block3ce2e202009-11-05 08:53:23 +0000650 } else {
651 ASSERT_EQ(array_type, kExternalUnsignedIntArray);
652 // The test is different for unsigned int values. Since we need
Andrei Popescu402d9372010-02-26 13:31:12 +0000653 // the value to be in the range of a positive smi, we can't
Steve Block3ce2e202009-11-05 08:53:23 +0000654 // handle either of the top two bits being set in the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000655 __ test(ecx, Immediate(0xC0000000));
Steve Block3ce2e202009-11-05 08:53:23 +0000656 __ j(not_zero, &box_int);
657 }
658
Andrei Popescu402d9372010-02-26 13:31:12 +0000659 __ mov(eax, ecx);
660 __ SmiTag(eax);
Steve Block3ce2e202009-11-05 08:53:23 +0000661 __ ret(0);
662
663 __ bind(&box_int);
664
665 // Allocate a HeapNumber for the int and perform int-to-double
666 // conversion.
667 if (array_type == kExternalIntArray) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000668 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000669 __ fild_s(Operand(esp, 0));
Andrei Popescu402d9372010-02-26 13:31:12 +0000670 __ pop(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000671 } else {
672 ASSERT(array_type == kExternalUnsignedIntArray);
673 // Need to zero-extend the value.
674 // There's no fild variant for unsigned values, so zero-extend
675 // to a 64-bit int manually.
676 __ push(Immediate(0));
Andrei Popescu402d9372010-02-26 13:31:12 +0000677 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000678 __ fild_d(Operand(esp, 0));
Andrei Popescu402d9372010-02-26 13:31:12 +0000679 __ pop(ecx);
680 __ pop(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000681 }
682 // FP(0): value
Andrei Popescu402d9372010-02-26 13:31:12 +0000683 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
Steve Block3ce2e202009-11-05 08:53:23 +0000684 // Set the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000685 __ mov(eax, ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000686 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
687 __ ret(0);
688 } else if (array_type == kExternalFloatArray) {
689 // For the floating-point array type, we need to always allocate a
690 // HeapNumber.
Andrei Popescu402d9372010-02-26 13:31:12 +0000691 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
Steve Block3ce2e202009-11-05 08:53:23 +0000692 // Set the value.
Andrei Popescu402d9372010-02-26 13:31:12 +0000693 __ mov(eax, ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000694 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
695 __ ret(0);
696 } else {
Andrei Popescu402d9372010-02-26 13:31:12 +0000697 __ mov(eax, ecx);
698 __ SmiTag(eax);
Steve Block3ce2e202009-11-05 08:53:23 +0000699 __ ret(0);
700 }
701
702 // If we fail allocation of the HeapNumber, we still have a value on
703 // top of the FPU stack. Remove it.
704 __ bind(&failed_allocation);
705 __ ffree();
706 __ fincstp();
707 // Fall through to slow case.
708
Andrei Popescu402d9372010-02-26 13:31:12 +0000709 // Slow case: Load key and receiver from stack and jump to runtime.
Steve Block3ce2e202009-11-05 08:53:23 +0000710 __ bind(&slow);
711 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000712 GenerateRuntimeGetProperty(masm);
713}
714
715
716void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
717 // ----------- S t a t e -------------
718 // -- eax : key
719 // -- edx : receiver
720 // -- esp[0] : return address
721 // -----------------------------------
722 Label slow;
723
724 // Check that the receiver isn't a smi.
725 __ test(edx, Immediate(kSmiTagMask));
726 __ j(zero, &slow, not_taken);
727
728 // Check that the key is a smi.
729 __ test(eax, Immediate(kSmiTagMask));
730 __ j(not_zero, &slow, not_taken);
731
732 // Get the map of the receiver.
733 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
734
735 // Check that it has indexed interceptor and access checks
736 // are not enabled for this object.
737 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
738 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
739 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
740 __ j(not_zero, &slow, not_taken);
741
742 // Everything is fine, call runtime.
743 __ pop(ecx);
744 __ push(edx); // receiver
745 __ push(eax); // key
746 __ push(ecx); // return address
747
748 // Perform tail call to the entry.
Steve Block6ded16b2010-05-10 14:33:55 +0100749 ExternalReference ref = ExternalReference(
750 IC_Utility(kKeyedLoadPropertyWithInterceptor));
751 __ TailCallExternalReference(ref, 2, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000752
753 __ bind(&slow);
754 GenerateMiss(masm);
Steve Block3ce2e202009-11-05 08:53:23 +0000755}
756
757
Steve Blocka7e24c12009-10-30 11:49:00 +0000758void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
759 // ----------- S t a t e -------------
760 // -- eax : value
Steve Block6ded16b2010-05-10 14:33:55 +0100761 // -- ecx : key
762 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000763 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 // -----------------------------------
765 Label slow, fast, array, extra, check_pixel_array;
766
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 // Check that the object isn't a smi.
768 __ test(edx, Immediate(kSmiTagMask));
769 __ j(zero, &slow, not_taken);
770 // Get the map from the receiver.
Steve Block6ded16b2010-05-10 14:33:55 +0100771 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 // Check that the receiver does not require access checks. We need
773 // to do this because this generic stub does not perform map checks.
Steve Block6ded16b2010-05-10 14:33:55 +0100774 __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
776 __ j(not_zero, &slow, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000777 // Check that the key is a smi.
Steve Block6ded16b2010-05-10 14:33:55 +0100778 __ test(ecx, Immediate(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 __ j(not_zero, &slow, not_taken);
Steve Block6ded16b2010-05-10 14:33:55 +0100780 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 __ j(equal, &array);
782 // Check that the object is some kind of JS object.
Steve Block6ded16b2010-05-10 14:33:55 +0100783 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
784 __ j(below, &slow, not_taken);
Steve Blocka7e24c12009-10-30 11:49:00 +0000785
786 // Object case: Check key against length in the elements array.
787 // eax: value
788 // edx: JSObject
Steve Block6ded16b2010-05-10 14:33:55 +0100789 // ecx: key (a smi)
790 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000791 // Check that the object is in fast mode (not dictionary).
Steve Block6ded16b2010-05-10 14:33:55 +0100792 __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
793 __ mov(ebx, Operand(ecx));
794 __ SmiUntag(ebx);
795 __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000796 __ j(below, &fast, taken);
797
Steve Block3ce2e202009-11-05 08:53:23 +0000798 // Slow case: call runtime.
Steve Blocka7e24c12009-10-30 11:49:00 +0000799 __ bind(&slow);
Andrei Popescu402d9372010-02-26 13:31:12 +0000800 GenerateRuntimeSetProperty(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000801
802 // Check whether the elements is a pixel array.
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 __ bind(&check_pixel_array);
Steve Block6ded16b2010-05-10 14:33:55 +0100804 // eax: value
805 // ecx: key
806 // edx: receiver
807 // edi: elements array
808 __ CheckMap(edi, Factory::pixel_array_map(), &slow, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000809 // Check that the value is a smi. If a conversion is needed call into the
810 // runtime to convert and clamp.
811 __ test(eax, Immediate(kSmiTagMask));
812 __ j(not_zero, &slow);
Steve Block6ded16b2010-05-10 14:33:55 +0100813 __ mov(ebx, ecx);
814 __ SmiUntag(ebx);
815 __ cmp(ebx, FieldOperand(edi, PixelArray::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 __ j(above_equal, &slow);
Steve Block6ded16b2010-05-10 14:33:55 +0100817 __ mov(ecx, eax); // Save the value. Key is not longer needed.
818 __ SmiUntag(ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 { // Clamp the value to [0..255].
Steve Block3ce2e202009-11-05 08:53:23 +0000820 Label done;
Steve Block6ded16b2010-05-10 14:33:55 +0100821 __ test(ecx, Immediate(0xFFFFFF00));
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 __ j(zero, &done);
Steve Block6ded16b2010-05-10 14:33:55 +0100823 __ setcc(negative, ecx); // 1 if negative, 0 if positive.
824 __ dec_b(ecx); // 0 if negative, 255 if positive.
Steve Blocka7e24c12009-10-30 11:49:00 +0000825 __ bind(&done);
826 }
Steve Block6ded16b2010-05-10 14:33:55 +0100827 __ mov(edi, FieldOperand(edi, PixelArray::kExternalPointerOffset));
828 __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
829 __ ret(0); // Return value in eax.
Steve Blocka7e24c12009-10-30 11:49:00 +0000830
831 // Extra capacity case: Check if there is extra capacity to
832 // perform the store and update the length. Used for adding one
833 // element to the array by writing to array[array.length].
834 __ bind(&extra);
835 // eax: value
Steve Block6ded16b2010-05-10 14:33:55 +0100836 // edx: receiver, a JSArray
837 // ecx: key, a smi.
838 // edi: receiver->elements, a FixedArray
839 // flags: compare (ecx, edx.length())
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 __ j(not_equal, &slow, not_taken); // do not leave holes in the array
Steve Block6ded16b2010-05-10 14:33:55 +0100841 __ mov(ebx, ecx);
842 __ SmiUntag(ebx); // untag
843 __ cmp(ebx, FieldOperand(edi, Array::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 __ j(above_equal, &slow, not_taken);
Steve Block6ded16b2010-05-10 14:33:55 +0100845 // Add 1 to receiver->length, and go to fast array write.
846 __ add(FieldOperand(edx, JSArray::kLengthOffset),
847 Immediate(1 << kSmiTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 __ jmp(&fast);
849
Steve Blocka7e24c12009-10-30 11:49:00 +0000850 // Array case: Get the length and the elements array from the JS
851 // array. Check that the array is in fast mode; if it is the
852 // length is always a smi.
853 __ bind(&array);
854 // eax: value
Steve Block6ded16b2010-05-10 14:33:55 +0100855 // edx: receiver, a JSArray
856 // ecx: key, a smi.
857 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
858 __ CheckMap(edi, Factory::fixed_array_map(), &check_pixel_array, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000859
860 // Check the key against the length in the array, compute the
861 // address to store into and fall through to fast case.
Steve Block6ded16b2010-05-10 14:33:55 +0100862 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 __ j(above_equal, &extra, not_taken);
864
865 // Fast case: Do the store.
866 __ bind(&fast);
867 // eax: value
Steve Block6ded16b2010-05-10 14:33:55 +0100868 // ecx: key (a smi)
869 // edx: receiver
870 // edi: FixedArray receiver->elements
871 __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax);
Steve Blocka7e24c12009-10-30 11:49:00 +0000872 // Update write barrier for the elements array address.
873 __ mov(edx, Operand(eax));
Steve Block6ded16b2010-05-10 14:33:55 +0100874 __ RecordWrite(edi, 0, edx, ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 __ ret(0);
876}
877
878
Steve Block3ce2e202009-11-05 08:53:23 +0000879void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
880 ExternalArrayType array_type) {
881 // ----------- S t a t e -------------
882 // -- eax : value
Steve Block6ded16b2010-05-10 14:33:55 +0100883 // -- ecx : key
884 // -- edx : receiver
Steve Block3ce2e202009-11-05 08:53:23 +0000885 // -- esp[0] : return address
Steve Block3ce2e202009-11-05 08:53:23 +0000886 // -----------------------------------
887 Label slow, check_heap_number;
888
Steve Block3ce2e202009-11-05 08:53:23 +0000889 // Check that the object isn't a smi.
890 __ test(edx, Immediate(kSmiTagMask));
891 __ j(zero, &slow);
892 // Get the map from the receiver.
Steve Block6ded16b2010-05-10 14:33:55 +0100893 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000894 // Check that the receiver does not require access checks. We need
895 // to do this because this generic stub does not perform map checks.
Steve Block6ded16b2010-05-10 14:33:55 +0100896 __ movzx_b(ebx, FieldOperand(edi, Map::kBitFieldOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000897 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
898 __ j(not_zero, &slow);
Steve Block3ce2e202009-11-05 08:53:23 +0000899 // Check that the key is a smi.
Steve Block6ded16b2010-05-10 14:33:55 +0100900 __ test(ecx, Immediate(kSmiTagMask));
Steve Block3ce2e202009-11-05 08:53:23 +0000901 __ j(not_zero, &slow);
902 // Get the instance type from the map of the receiver.
Steve Block6ded16b2010-05-10 14:33:55 +0100903 __ CmpInstanceType(edi, JS_OBJECT_TYPE);
Steve Block3ce2e202009-11-05 08:53:23 +0000904 __ j(not_equal, &slow);
905
906 // Check that the elements array is the appropriate type of
907 // ExternalArray.
908 // eax: value
Steve Block6ded16b2010-05-10 14:33:55 +0100909 // edx: receiver, a JSObject
910 // ecx: key, a smi
911 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
912 __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)),
913 &slow, true);
Steve Block3ce2e202009-11-05 08:53:23 +0000914
915 // Check that the index is in range.
Steve Block6ded16b2010-05-10 14:33:55 +0100916 __ mov(ebx, ecx);
917 __ SmiUntag(ebx);
918 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000919 // Unsigned comparison catches both negative and too-large values.
920 __ j(above_equal, &slow);
921
922 // Handle both smis and HeapNumbers in the fast path. Go to the
923 // runtime for all other kinds of values.
924 // eax: value
Steve Block6ded16b2010-05-10 14:33:55 +0100925 // edx: receiver
926 // ecx: key
927 // edi: elements array
Steve Block3ce2e202009-11-05 08:53:23 +0000928 // ebx: untagged index
929 __ test(eax, Immediate(kSmiTagMask));
930 __ j(not_equal, &check_heap_number);
931 // smi case
Steve Block6ded16b2010-05-10 14:33:55 +0100932 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
933 __ SmiUntag(ecx);
934 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000935 // ecx: base pointer of external storage
936 switch (array_type) {
937 case kExternalByteArray:
938 case kExternalUnsignedByteArray:
Steve Block6ded16b2010-05-10 14:33:55 +0100939 __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000940 break;
941 case kExternalShortArray:
942 case kExternalUnsignedShortArray:
Steve Block6ded16b2010-05-10 14:33:55 +0100943 __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000944 break;
945 case kExternalIntArray:
946 case kExternalUnsignedIntArray:
Steve Block6ded16b2010-05-10 14:33:55 +0100947 __ mov(Operand(edi, ebx, times_4, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000948 break;
949 case kExternalFloatArray:
950 // Need to perform int-to-float conversion.
Steve Block6ded16b2010-05-10 14:33:55 +0100951 __ push(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000952 __ fild_s(Operand(esp, 0));
Steve Block6ded16b2010-05-10 14:33:55 +0100953 __ pop(ecx);
954 __ fstp_s(Operand(edi, ebx, times_4, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000955 break;
956 default:
957 UNREACHABLE();
958 break;
959 }
Steve Block6ded16b2010-05-10 14:33:55 +0100960 __ ret(0); // Return the original value.
Steve Block3ce2e202009-11-05 08:53:23 +0000961
962 __ bind(&check_heap_number);
Steve Block6ded16b2010-05-10 14:33:55 +0100963 // eax: value
964 // edx: receiver
965 // ecx: key
966 // edi: elements array
967 // ebx: untagged index
Steve Block3ce2e202009-11-05 08:53:23 +0000968 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
969 Immediate(Factory::heap_number_map()));
970 __ j(not_equal, &slow);
971
972 // The WebGL specification leaves the behavior of storing NaN and
973 // +/-Infinity into integer arrays basically undefined. For more
974 // reproducible behavior, convert these to zero.
975 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
Steve Block6ded16b2010-05-10 14:33:55 +0100976 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
Steve Block3ce2e202009-11-05 08:53:23 +0000977 // ebx: untagged index
Steve Block6ded16b2010-05-10 14:33:55 +0100978 // edi: base pointer of external storage
Steve Block3ce2e202009-11-05 08:53:23 +0000979 // top of FPU stack: value
980 if (array_type == kExternalFloatArray) {
Steve Block6ded16b2010-05-10 14:33:55 +0100981 __ fstp_s(Operand(edi, ebx, times_4, 0));
Steve Block3ce2e202009-11-05 08:53:23 +0000982 __ ret(0);
983 } else {
984 // Need to perform float-to-int conversion.
985 // Test the top of the FP stack for NaN.
986 Label is_nan;
987 __ fucomi(0);
988 __ j(parity_even, &is_nan);
989
990 if (array_type != kExternalUnsignedIntArray) {
Steve Block6ded16b2010-05-10 14:33:55 +0100991 __ push(ecx); // Make room on stack
Steve Block3ce2e202009-11-05 08:53:23 +0000992 __ fistp_s(Operand(esp, 0));
Steve Block6ded16b2010-05-10 14:33:55 +0100993 __ pop(ecx);
Steve Block3ce2e202009-11-05 08:53:23 +0000994 } else {
995 // fistp stores values as signed integers.
996 // To represent the entire range, we need to store as a 64-bit
997 // int and discard the high 32 bits.
Steve Block6ded16b2010-05-10 14:33:55 +0100998 __ sub(Operand(esp), Immediate(2 * kPointerSize));
Steve Block3ce2e202009-11-05 08:53:23 +0000999 __ fistp_d(Operand(esp, 0));
Steve Block6ded16b2010-05-10 14:33:55 +01001000 __ pop(ecx);
1001 __ add(Operand(esp), Immediate(kPointerSize));
Steve Block3ce2e202009-11-05 08:53:23 +00001002 }
Steve Block6ded16b2010-05-10 14:33:55 +01001003 // ecx: untagged integer value
Steve Block3ce2e202009-11-05 08:53:23 +00001004 switch (array_type) {
1005 case kExternalByteArray:
1006 case kExternalUnsignedByteArray:
Steve Block6ded16b2010-05-10 14:33:55 +01001007 __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001008 break;
1009 case kExternalShortArray:
1010 case kExternalUnsignedShortArray:
Steve Block6ded16b2010-05-10 14:33:55 +01001011 __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001012 break;
1013 case kExternalIntArray:
1014 case kExternalUnsignedIntArray: {
1015 // We also need to explicitly check for +/-Infinity. These are
1016 // converted to MIN_INT, but we need to be careful not to
1017 // confuse with legal uses of MIN_INT.
1018 Label not_infinity;
1019 // This test would apparently detect both NaN and Infinity,
1020 // but we've already checked for NaN using the FPU hardware
1021 // above.
Steve Block6ded16b2010-05-10 14:33:55 +01001022 __ mov_w(edx, FieldOperand(eax, HeapNumber::kValueOffset + 6));
1023 __ and_(edx, 0x7FF0);
1024 __ cmp(edx, 0x7FF0);
Steve Block3ce2e202009-11-05 08:53:23 +00001025 __ j(not_equal, &not_infinity);
Steve Block6ded16b2010-05-10 14:33:55 +01001026 __ mov(ecx, 0);
Steve Block3ce2e202009-11-05 08:53:23 +00001027 __ bind(&not_infinity);
Steve Block6ded16b2010-05-10 14:33:55 +01001028 __ mov(Operand(edi, ebx, times_4, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001029 break;
1030 }
1031 default:
1032 UNREACHABLE();
1033 break;
1034 }
Steve Block6ded16b2010-05-10 14:33:55 +01001035 __ ret(0); // Return original value.
Steve Block3ce2e202009-11-05 08:53:23 +00001036
1037 __ bind(&is_nan);
1038 __ ffree();
1039 __ fincstp();
1040 switch (array_type) {
1041 case kExternalByteArray:
1042 case kExternalUnsignedByteArray:
Steve Block6ded16b2010-05-10 14:33:55 +01001043 __ mov_b(Operand(edi, ebx, times_1, 0), 0);
Steve Block3ce2e202009-11-05 08:53:23 +00001044 break;
1045 case kExternalShortArray:
1046 case kExternalUnsignedShortArray:
Steve Block6ded16b2010-05-10 14:33:55 +01001047 __ xor_(ecx, Operand(ecx));
1048 __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
Steve Block3ce2e202009-11-05 08:53:23 +00001049 break;
1050 case kExternalIntArray:
1051 case kExternalUnsignedIntArray:
Steve Block6ded16b2010-05-10 14:33:55 +01001052 __ mov(Operand(edi, ebx, times_4, 0), Immediate(0));
Steve Block3ce2e202009-11-05 08:53:23 +00001053 break;
1054 default:
1055 UNREACHABLE();
1056 break;
1057 }
Steve Block6ded16b2010-05-10 14:33:55 +01001058 __ ret(0); // Return the original value.
Steve Block3ce2e202009-11-05 08:53:23 +00001059 }
1060
1061 // Slow case: call runtime.
1062 __ bind(&slow);
Andrei Popescu402d9372010-02-26 13:31:12 +00001063 GenerateRuntimeSetProperty(masm);
Steve Block3ce2e202009-11-05 08:53:23 +00001064}
1065
1066
Steve Blocka7e24c12009-10-30 11:49:00 +00001067// Defined in ic.cc.
1068Object* CallIC_Miss(Arguments args);
1069
1070void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1071 // ----------- S t a t e -------------
Leon Clarkee46be812010-01-19 14:06:41 +00001072 // -- ecx : name
1073 // -- esp[0] : return address
1074 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1075 // -- ...
1076 // -- esp[(argc + 1) * 4] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001077 // -----------------------------------
1078 Label number, non_number, non_string, boolean, probe, miss;
1079
1080 // Get the receiver of the function from the stack; 1 ~ return address.
1081 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00001082
1083 // Probe the stub cache.
1084 Code::Flags flags =
1085 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
1086 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, eax);
1087
1088 // If the stub cache probing failed, the receiver might be a value.
1089 // For value objects, we use the map of the prototype objects for
1090 // the corresponding JSValue for the cache and that is what we need
1091 // to probe.
1092 //
1093 // Check for number.
1094 __ test(edx, Immediate(kSmiTagMask));
1095 __ j(zero, &number, not_taken);
1096 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
1097 __ j(not_equal, &non_number, taken);
1098 __ bind(&number);
1099 StubCompiler::GenerateLoadGlobalFunctionPrototype(
1100 masm, Context::NUMBER_FUNCTION_INDEX, edx);
1101 __ jmp(&probe);
1102
1103 // Check for string.
1104 __ bind(&non_number);
1105 __ cmp(ebx, FIRST_NONSTRING_TYPE);
1106 __ j(above_equal, &non_string, taken);
1107 StubCompiler::GenerateLoadGlobalFunctionPrototype(
1108 masm, Context::STRING_FUNCTION_INDEX, edx);
1109 __ jmp(&probe);
1110
1111 // Check for boolean.
1112 __ bind(&non_string);
1113 __ cmp(edx, Factory::true_value());
1114 __ j(equal, &boolean, not_taken);
1115 __ cmp(edx, Factory::false_value());
1116 __ j(not_equal, &miss, taken);
1117 __ bind(&boolean);
1118 StubCompiler::GenerateLoadGlobalFunctionPrototype(
1119 masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
1120
1121 // Probe the stub cache for the value object.
1122 __ bind(&probe);
1123 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1124
1125 // Cache miss: Jump to runtime.
1126 __ bind(&miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001127 GenerateMiss(masm, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +00001128}
1129
1130
1131static void GenerateNormalHelper(MacroAssembler* masm,
1132 int argc,
1133 bool is_global_object,
1134 Label* miss) {
Leon Clarkee46be812010-01-19 14:06:41 +00001135 // ----------- S t a t e -------------
1136 // -- ecx : name
1137 // -- edx : receiver
1138 // -- esp[0] : return address
1139 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1140 // -- ...
1141 // -- esp[(argc + 1) * 4] : receiver
1142 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001143
Leon Clarkee46be812010-01-19 14:06:41 +00001144 // Search dictionary - put result in register edi.
1145 __ mov(edi, edx);
Andrei Popescu402d9372010-02-26 13:31:12 +00001146 GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY);
Leon Clarkee46be812010-01-19 14:06:41 +00001147
1148 // Check that the result is not a smi.
1149 __ test(edi, Immediate(kSmiTagMask));
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 __ j(zero, miss, not_taken);
1151
Leon Clarkee46be812010-01-19 14:06:41 +00001152 // Check that the value is a JavaScript function, fetching its map into eax.
1153 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
Steve Blocka7e24c12009-10-30 11:49:00 +00001154 __ j(not_equal, miss, not_taken);
1155
Leon Clarkee46be812010-01-19 14:06:41 +00001156 // Patch the receiver on stack with the global proxy if necessary.
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 if (is_global_object) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001158 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1159 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1160 }
1161
1162 // Invoke the function.
1163 ParameterCount actual(argc);
1164 __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1165}
1166
1167
1168void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
1169 // ----------- S t a t e -------------
Leon Clarkee46be812010-01-19 14:06:41 +00001170 // -- ecx : name
1171 // -- esp[0] : return address
1172 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1173 // -- ...
1174 // -- esp[(argc + 1) * 4] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001175 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001176 Label miss, global_object, non_global_object;
1177
1178 // Get the receiver of the function from the stack; 1 ~ return address.
1179 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00001180
1181 // Check that the receiver isn't a smi.
1182 __ test(edx, Immediate(kSmiTagMask));
1183 __ j(zero, &miss, not_taken);
1184
1185 // Check that the receiver is a valid JS object.
1186 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1187 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceTypeOffset));
1188 __ cmp(eax, FIRST_JS_OBJECT_TYPE);
1189 __ j(below, &miss, not_taken);
1190
1191 // If this assert fails, we have to check upper bound too.
1192 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1193
1194 // Check for access to global object.
1195 __ cmp(eax, JS_GLOBAL_OBJECT_TYPE);
1196 __ j(equal, &global_object);
1197 __ cmp(eax, JS_BUILTINS_OBJECT_TYPE);
1198 __ j(not_equal, &non_global_object);
1199
1200 // Accessing global object: Load and invoke.
1201 __ bind(&global_object);
1202 // Check that the global object does not require access checks.
1203 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1204 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1205 __ j(not_equal, &miss, not_taken);
1206 GenerateNormalHelper(masm, argc, true, &miss);
1207
1208 // Accessing non-global object: Check for access to global proxy.
1209 Label global_proxy, invoke;
1210 __ bind(&non_global_object);
1211 __ cmp(eax, JS_GLOBAL_PROXY_TYPE);
1212 __ j(equal, &global_proxy, not_taken);
1213 // Check that the non-global, non-global-proxy object does not
1214 // require access checks.
1215 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1216 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1217 __ j(not_equal, &miss, not_taken);
1218 __ bind(&invoke);
1219 GenerateNormalHelper(masm, argc, false, &miss);
1220
1221 // Global object proxy access: Check access rights.
1222 __ bind(&global_proxy);
1223 __ CheckAccessGlobalProxy(edx, eax, &miss);
1224 __ jmp(&invoke);
1225
1226 // Cache miss: Jump to runtime.
1227 __ bind(&miss);
Leon Clarkee46be812010-01-19 14:06:41 +00001228 GenerateMiss(masm, argc);
Steve Blocka7e24c12009-10-30 11:49:00 +00001229}
1230
1231
Leon Clarkee46be812010-01-19 14:06:41 +00001232void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001233 // ----------- S t a t e -------------
Leon Clarkee46be812010-01-19 14:06:41 +00001234 // -- ecx : name
1235 // -- esp[0] : return address
1236 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1237 // -- ...
1238 // -- esp[(argc + 1) * 4] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 // -----------------------------------
1240
1241 // Get the receiver of the function from the stack; 1 ~ return address.
1242 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00001243
1244 // Enter an internal frame.
1245 __ EnterInternalFrame();
1246
1247 // Push the receiver and the name of the function.
1248 __ push(edx);
Leon Clarkee46be812010-01-19 14:06:41 +00001249 __ push(ecx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001250
1251 // Call the entry.
1252 CEntryStub stub(1);
1253 __ mov(eax, Immediate(2));
Leon Clarkee46be812010-01-19 14:06:41 +00001254 __ mov(ebx, Immediate(ExternalReference(IC_Utility(kCallIC_Miss))));
Steve Blocka7e24c12009-10-30 11:49:00 +00001255 __ CallStub(&stub);
1256
1257 // Move result to edi and exit the internal frame.
1258 __ mov(edi, eax);
1259 __ LeaveInternalFrame();
1260
1261 // Check if the receiver is a global object of some sort.
1262 Label invoke, global;
1263 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
1264 __ test(edx, Immediate(kSmiTagMask));
1265 __ j(zero, &invoke, not_taken);
Leon Clarkee46be812010-01-19 14:06:41 +00001266 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1267 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1268 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001269 __ j(equal, &global);
Leon Clarkee46be812010-01-19 14:06:41 +00001270 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001271 __ j(not_equal, &invoke);
1272
1273 // Patch the receiver on the stack.
1274 __ bind(&global);
1275 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1276 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1277
1278 // Invoke the function.
1279 ParameterCount actual(argc);
1280 __ bind(&invoke);
1281 __ InvokeFunction(edi, actual, JUMP_FUNCTION);
1282}
1283
1284
1285// Defined in ic.cc.
1286Object* LoadIC_Miss(Arguments args);
1287
1288void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1289 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001290 // -- eax : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001291 // -- ecx : name
1292 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001293 // -----------------------------------
1294
Steve Blocka7e24c12009-10-30 11:49:00 +00001295 // Probe the stub cache.
1296 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1297 NOT_IN_LOOP,
1298 MONOMORPHIC);
1299 StubCache::GenerateProbe(masm, flags, eax, ecx, ebx, edx);
1300
1301 // Cache miss: Jump to runtime.
Andrei Popescu402d9372010-02-26 13:31:12 +00001302 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001303}
1304
1305
1306void LoadIC::GenerateNormal(MacroAssembler* masm) {
1307 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001308 // -- eax : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 // -- ecx : name
1310 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001311 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 Label miss, probe, global;
1313
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 // Check that the receiver isn't a smi.
1315 __ test(eax, Immediate(kSmiTagMask));
1316 __ j(zero, &miss, not_taken);
1317
1318 // Check that the receiver is a valid JS object.
1319 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1320 __ movzx_b(edx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1321 __ cmp(edx, FIRST_JS_OBJECT_TYPE);
1322 __ j(less, &miss, not_taken);
1323
1324 // If this assert fails, we have to check upper bound too.
1325 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
1326
1327 // Check for access to global object (unlikely).
1328 __ cmp(edx, JS_GLOBAL_PROXY_TYPE);
1329 __ j(equal, &global, not_taken);
1330
1331 // Check for non-global object that requires access check.
1332 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
1333 __ test(ebx, Immediate(1 << Map::kIsAccessCheckNeeded));
1334 __ j(not_zero, &miss, not_taken);
1335
1336 // Search the dictionary placing the result in eax.
1337 __ bind(&probe);
Andrei Popescu402d9372010-02-26 13:31:12 +00001338 GenerateDictionaryLoad(masm,
1339 &miss,
1340 eax,
1341 ecx,
1342 edx,
1343 edi,
1344 ebx,
1345 CHECK_DICTIONARY);
1346 __ mov(eax, edi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 __ ret(0);
1348
1349 // Global object access: Check access rights.
1350 __ bind(&global);
1351 __ CheckAccessGlobalProxy(eax, edx, &miss);
1352 __ jmp(&probe);
1353
1354 // Cache miss: Restore receiver from stack and jump to runtime.
1355 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +00001356 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001357}
1358
1359
1360void LoadIC::GenerateMiss(MacroAssembler* masm) {
1361 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001362 // -- eax : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 // -- ecx : name
1364 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 // -----------------------------------
1366
Steve Blocka7e24c12009-10-30 11:49:00 +00001367 __ pop(ebx);
1368 __ push(eax); // receiver
1369 __ push(ecx); // name
1370 __ push(ebx); // return address
1371
1372 // Perform tail call to the entry.
Steve Block6ded16b2010-05-10 14:33:55 +01001373 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
1374 __ TailCallExternalReference(ref, 2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001375}
1376
1377
1378// One byte opcode for test eax,0xXXXXXXXX.
1379static const byte kTestEaxByte = 0xA9;
1380
1381
1382void LoadIC::ClearInlinedVersion(Address address) {
1383 // Reset the map check of the inlined inobject property load (if
1384 // present) to guarantee failure by holding an invalid map (the null
1385 // value). The offset can be patched to anything.
1386 PatchInlinedLoad(address, Heap::null_value(), kMaxInt);
1387}
1388
1389
1390void KeyedLoadIC::ClearInlinedVersion(Address address) {
1391 // Insert null as the map to check for to make sure the map check fails
1392 // sending control flow to the IC instead of the inlined version.
1393 PatchInlinedLoad(address, Heap::null_value());
1394}
1395
1396
1397void KeyedStoreIC::ClearInlinedVersion(Address address) {
1398 // Insert null as the elements map to check for. This will make
1399 // sure that the elements fast-case map check fails so that control
1400 // flows to the IC instead of the inlined version.
1401 PatchInlinedStore(address, Heap::null_value());
1402}
1403
1404
1405void KeyedStoreIC::RestoreInlinedVersion(Address address) {
1406 // Restore the fast-case elements map check so that the inlined
1407 // version can be used again.
1408 PatchInlinedStore(address, Heap::fixed_array_map());
1409}
1410
1411
1412bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
1413 // The address of the instruction following the call.
1414 Address test_instruction_address =
1415 address + Assembler::kCallTargetAddressOffset;
1416 // If the instruction following the call is not a test eax, nothing
1417 // was inlined.
1418 if (*test_instruction_address != kTestEaxByte) return false;
1419
1420 Address delta_address = test_instruction_address + 1;
1421 // The delta to the start of the map check instruction.
1422 int delta = *reinterpret_cast<int*>(delta_address);
1423
1424 // The map address is the last 4 bytes of the 7-byte
1425 // operand-immediate compare instruction, so we add 3 to get the
1426 // offset to the last 4 bytes.
1427 Address map_address = test_instruction_address + delta + 3;
1428 *(reinterpret_cast<Object**>(map_address)) = map;
1429
1430 // The offset is in the last 4 bytes of a six byte
1431 // memory-to-register move instruction, so we add 2 to get the
1432 // offset to the last 4 bytes.
1433 Address offset_address =
1434 test_instruction_address + delta + kOffsetToLoadInstruction + 2;
1435 *reinterpret_cast<int*>(offset_address) = offset - kHeapObjectTag;
1436 return true;
1437}
1438
1439
1440static bool PatchInlinedMapCheck(Address address, Object* map) {
1441 Address test_instruction_address =
1442 address + Assembler::kCallTargetAddressOffset;
1443 // The keyed load has a fast inlined case if the IC call instruction
1444 // is immediately followed by a test instruction.
1445 if (*test_instruction_address != kTestEaxByte) return false;
1446
1447 // Fetch the offset from the test instruction to the map cmp
1448 // instruction. This offset is stored in the last 4 bytes of the 5
1449 // byte test instruction.
1450 Address delta_address = test_instruction_address + 1;
1451 int delta = *reinterpret_cast<int*>(delta_address);
1452 // Compute the map address. The map address is in the last 4 bytes
1453 // of the 7-byte operand-immediate compare instruction, so we add 3
1454 // to the offset to get the map address.
1455 Address map_address = test_instruction_address + delta + 3;
1456 // Patch the map check.
1457 *(reinterpret_cast<Object**>(map_address)) = map;
1458 return true;
1459}
1460
1461
1462bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1463 return PatchInlinedMapCheck(address, map);
1464}
1465
1466
1467bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
1468 return PatchInlinedMapCheck(address, map);
1469}
1470
1471
1472// Defined in ic.cc.
1473Object* KeyedLoadIC_Miss(Arguments args);
1474
1475
1476void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
1477 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +00001478 // -- eax : key
1479 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001481 // -----------------------------------
1482
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 __ pop(ebx);
Andrei Popescu402d9372010-02-26 13:31:12 +00001484 __ push(edx); // receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 __ push(eax); // name
1486 __ push(ebx); // return address
1487
1488 // Perform tail call to the entry.
Steve Block6ded16b2010-05-10 14:33:55 +01001489 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1490 __ TailCallExternalReference(ref, 2, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001491}
1492
1493
1494void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1495 // ----------- S t a t e -------------
1496 // -- eax : key
1497 // -- edx : receiver
1498 // -- esp[0] : return address
1499 // -----------------------------------
1500
1501 __ pop(ebx);
1502 __ push(edx); // receiver
1503 __ push(eax); // name
1504 __ push(ebx); // return address
1505
1506 // Perform tail call to the entry.
Steve Block6ded16b2010-05-10 14:33:55 +01001507 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001508}
1509
1510
1511void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1512 // ----------- S t a t e -------------
1513 // -- eax : value
1514 // -- ecx : name
Leon Clarke4515c472010-02-03 11:58:03 +00001515 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001516 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001517 // -----------------------------------
1518
Steve Blocka7e24c12009-10-30 11:49:00 +00001519 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1520 NOT_IN_LOOP,
1521 MONOMORPHIC);
1522 StubCache::GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
1523
1524 // Cache miss: Jump to runtime.
Leon Clarke4515c472010-02-03 11:58:03 +00001525 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001526}
1527
1528
Leon Clarke4515c472010-02-03 11:58:03 +00001529void StoreIC::GenerateMiss(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 // ----------- S t a t e -------------
1531 // -- eax : value
1532 // -- ecx : name
Leon Clarke4515c472010-02-03 11:58:03 +00001533 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001535 // -----------------------------------
1536
Steve Blocka7e24c12009-10-30 11:49:00 +00001537 __ pop(ebx);
Leon Clarke4515c472010-02-03 11:58:03 +00001538 __ push(edx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001539 __ push(ecx);
1540 __ push(eax);
1541 __ push(ebx);
1542
1543 // Perform tail call to the entry.
Steve Block6ded16b2010-05-10 14:33:55 +01001544 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1545 __ TailCallExternalReference(ref, 3, 1);
1546}
1547
1548
1549void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1550 // ----------- S t a t e -------------
1551 // -- eax : value
1552 // -- ecx : name
1553 // -- edx : receiver
1554 // -- esp[0] : return address
1555 // -----------------------------------
1556 //
1557 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1558 // (currently anything except for external and pixel arrays which means
1559 // anything with elements of FixedArray type.), but currently is restricted
1560 // to JSArray.
1561 // Value must be a number, but only smis are accepted as the most common case.
1562
1563 Label miss;
1564
1565 Register receiver = edx;
1566 Register value = eax;
1567 Register scratch = ebx;
1568
1569 // Check that the receiver isn't a smi.
1570 __ test(receiver, Immediate(kSmiTagMask));
1571 __ j(zero, &miss, not_taken);
1572
1573 // Check that the object is a JS array.
1574 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
1575 __ j(not_equal, &miss, not_taken);
1576
1577 // Check that elements are FixedArray.
1578 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1579 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
1580 __ j(not_equal, &miss, not_taken);
1581
1582 // Check that value is a smi.
1583 __ test(value, Immediate(kSmiTagMask));
1584 __ j(not_zero, &miss, not_taken);
1585
1586 // Prepare tail call to StoreIC_ArrayLength.
1587 __ pop(scratch);
1588 __ push(receiver);
1589 __ push(value);
1590 __ push(scratch); // return address
1591
1592 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1593 __ TailCallExternalReference(ref, 2, 1);
1594
1595 __ bind(&miss);
1596
1597 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001598}
1599
1600
1601// Defined in ic.cc.
1602Object* KeyedStoreIC_Miss(Arguments args);
1603
Andrei Popescu402d9372010-02-26 13:31:12 +00001604void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001605 // ----------- S t a t e -------------
1606 // -- eax : value
Steve Block6ded16b2010-05-10 14:33:55 +01001607 // -- ecx : key
1608 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001609 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001610 // -----------------------------------
1611
Steve Block6ded16b2010-05-10 14:33:55 +01001612 __ pop(ebx);
1613 __ push(edx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001614 __ push(ecx);
Steve Block6ded16b2010-05-10 14:33:55 +01001615 __ push(eax);
1616 __ push(ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001617
1618 // Do tail-call to runtime routine.
Steve Block6ded16b2010-05-10 14:33:55 +01001619 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001620}
1621
1622
Andrei Popescu402d9372010-02-26 13:31:12 +00001623void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001624 // ----------- S t a t e -------------
1625 // -- eax : value
Steve Block6ded16b2010-05-10 14:33:55 +01001626 // -- ecx : key
1627 // -- edx : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001628 // -- esp[0] : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001629 // -----------------------------------
1630
Steve Block6ded16b2010-05-10 14:33:55 +01001631 __ pop(ebx);
1632 __ push(edx);
Andrei Popescu402d9372010-02-26 13:31:12 +00001633 __ push(ecx);
Steve Block6ded16b2010-05-10 14:33:55 +01001634 __ push(eax);
1635 __ push(ebx);
Steve Blocka7e24c12009-10-30 11:49:00 +00001636
1637 // Do tail-call to runtime routine.
Steve Block6ded16b2010-05-10 14:33:55 +01001638 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1639 __ TailCallExternalReference(ref, 3, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001640}
1641
1642#undef __
1643
1644
1645} } // namespace v8::internal