blob: 761e05ae466df7ce6709006b63c26925aa59b392 [file] [log] [blame]
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002// 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
kasperl@chromium.org71affb52009-05-26 05:44:31 +000028#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_X64)
31
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000033#include "ic-inl.h"
34#include "runtime.h"
35#include "stub-cache.h"
36
37namespace v8 {
38namespace internal {
39
ager@chromium.org5aa501c2009-06-23 07:57:28 +000040// ----------------------------------------------------------------------------
41// Static IC stub generators.
42//
43
44#define __ ACCESS_MASM(masm)
45
kasperl@chromium.org71affb52009-05-26 05:44:31 +000046
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000047static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
48 Register type,
49 Label* global_object) {
50 // Register usage:
51 // type: holds the receiver instance type on entry.
52 __ cmpb(type, Immediate(JS_GLOBAL_OBJECT_TYPE));
53 __ j(equal, global_object);
54 __ cmpb(type, Immediate(JS_BUILTINS_OBJECT_TYPE));
55 __ j(equal, global_object);
56 __ cmpb(type, Immediate(JS_GLOBAL_PROXY_TYPE));
57 __ j(equal, global_object);
58}
59
60
61// Generated code falls through if the receiver is a regular non-global
62// JS object with slow properties and no interceptors.
ulan@chromium.org750145a2013-03-07 15:14:13 +000063static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
64 Register receiver,
65 Register r0,
66 Register r1,
67 Label* miss) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000068 // Register usage:
69 // receiver: holds the receiver on entry and is unchanged.
70 // r0: used to hold receiver instance type.
71 // Holds the property dictionary on fall through.
72 // r1: used to hold receivers map.
73
74 __ JumpIfSmi(receiver, miss);
75
76 // Check that the receiver is a valid JS object.
77 __ movq(r1, FieldOperand(receiver, HeapObject::kMapOffset));
78 __ movb(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000079 __ cmpb(r0, Immediate(FIRST_SPEC_OBJECT_TYPE));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000080 __ j(below, miss);
81
82 // If this assert fails, we have to check upper bound too.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000083 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000084
85 GenerateGlobalInstanceTypeCheck(masm, r0, miss);
86
87 // Check for non-global object that requires access check.
88 __ testb(FieldOperand(r1, Map::kBitFieldOffset),
89 Immediate((1 << Map::kIsAccessCheckNeeded) |
90 (1 << Map::kHasNamedInterceptor)));
91 __ j(not_zero, miss);
92
93 __ movq(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
94 __ CompareRoot(FieldOperand(r0, HeapObject::kMapOffset),
95 Heap::kHashTableMapRootIndex);
96 __ j(not_equal, miss);
97}
98
99
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000100
101// Helper function used to load a property from a dictionary backing storage.
102// This function may return false negatives, so miss_label
103// must always call a backup property load that is complete.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000104// This function is safe to call if name is not an internalized string,
105// and will jump to the miss_label in that case.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000106// The generated code assumes that the receiver has slow properties,
107// is not a global object and does not have interceptors.
108static void GenerateDictionaryLoad(MacroAssembler* masm,
109 Label* miss_label,
110 Register elements,
111 Register name,
112 Register r0,
113 Register r1,
114 Register result) {
115 // Register use:
116 //
117 // elements - holds the property dictionary on entry and is unchanged.
118 //
119 // name - holds the name of the property on entry and is unchanged.
120 //
121 // r0 - used to hold the capacity of the property dictionary.
122 //
123 // r1 - used to hold the index into the property dictionary.
124 //
125 // result - holds the result on exit if the load succeeded.
126
127 Label done;
128
129 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000130 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
131 miss_label,
132 &done,
133 elements,
134 name,
135 r0,
136 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000137
verwaest@chromium.orgde64f722012-08-16 15:44:54 +0000138 // If probing finds an entry in the dictionary, r1 contains the
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000139 // index into the dictionary. Check that the value is a normal
140 // property.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000141 __ bind(&done);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000142 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000143 NameDictionary::kHeaderSize +
144 NameDictionary::kElementsStartIndex * kPointerSize;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000146 __ Test(Operand(elements, r1, times_pointer_size,
147 kDetailsOffset - kHeapObjectTag),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000148 Smi::FromInt(PropertyDetails::TypeField::kMask));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000149 __ j(not_zero, miss_label);
150
151 // Get the value at the masked, scaled index.
152 const int kValueOffset = kElementsStartOffset + kPointerSize;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000153 __ movq(result,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000154 Operand(elements, r1, times_pointer_size,
155 kValueOffset - kHeapObjectTag));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000156}
157
158
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000159// Helper function used to store a property to a dictionary backing
160// storage. This function may fail to store a property even though it
161// is in the dictionary, so code at miss_label must always call a
162// backup property store that is complete. This function is safe to
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000163// call if name is not an internalized string, and will jump to the miss_label
164// in that case. The generated code assumes that the receiver has slow
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000165// properties, is not a global object and does not have interceptors.
166static void GenerateDictionaryStore(MacroAssembler* masm,
167 Label* miss_label,
168 Register elements,
169 Register name,
170 Register value,
171 Register scratch0,
172 Register scratch1) {
173 // Register use:
174 //
175 // elements - holds the property dictionary on entry and is clobbered.
176 //
177 // name - holds the name of the property on entry and is unchanged.
178 //
179 // value - holds the value to store and is unchanged.
180 //
verwaest@chromium.orgde64f722012-08-16 15:44:54 +0000181 // scratch0 - used during the positive dictionary lookup and is clobbered.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000182 //
verwaest@chromium.orgde64f722012-08-16 15:44:54 +0000183 // scratch1 - used for index into the property dictionary and is clobbered.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000184 Label done;
185
186 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000187 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
188 miss_label,
189 &done,
190 elements,
191 name,
192 scratch0,
193 scratch1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000194
195 // If probing finds an entry in the dictionary, scratch0 contains the
196 // index into the dictionary. Check that the value is a normal
197 // property that is not read only.
198 __ bind(&done);
199 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000200 NameDictionary::kHeaderSize +
201 NameDictionary::kElementsStartIndex * kPointerSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000202 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 const int kTypeAndReadOnlyMask =
204 (PropertyDetails::TypeField::kMask |
205 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000206 __ Test(Operand(elements,
207 scratch1,
208 times_pointer_size,
209 kDetailsOffset - kHeapObjectTag),
210 Smi::FromInt(kTypeAndReadOnlyMask));
211 __ j(not_zero, miss_label);
212
213 // Store the value at the masked, scaled index.
214 const int kValueOffset = kElementsStartOffset + kPointerSize;
215 __ lea(scratch1, Operand(elements,
216 scratch1,
217 times_pointer_size,
218 kValueOffset - kHeapObjectTag));
219 __ movq(Operand(scratch1, 0), value);
220
221 // Update write barrier. Make sure not to clobber the value.
222 __ movq(scratch0, value);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000223 __ RecordWrite(elements, scratch1, scratch0, kDontSaveFPRegs);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000224}
225
226
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000227// Checks the receiver for special cases (value type, slow case bits).
228// Falls through for regular JS object.
229static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
230 Register receiver,
231 Register map,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000232 int interceptor_bit,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000233 Label* slow) {
234 // Register use:
235 // receiver - holds the receiver and is unchanged.
236 // Scratch registers:
237 // map - used to hold the map of the receiver.
238
239 // Check that the object isn't a smi.
240 __ JumpIfSmi(receiver, slow);
241
242 // Check that the object is some kind of JS object EXCEPT JS Value type.
243 // In the case that the object is a value-wrapper object,
244 // we enter the runtime system to make sure that indexing
245 // into string objects work as intended.
246 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
247 __ CmpObjectType(receiver, JS_OBJECT_TYPE, map);
248 __ j(below, slow);
249
250 // Check bit field.
251 __ testb(FieldOperand(map, Map::kBitFieldOffset),
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000252 Immediate((1 << Map::kIsAccessCheckNeeded) |
253 (1 << interceptor_bit)));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000254 __ j(not_zero, slow);
255}
256
257
258// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000259// If not_fast_array is NULL, doesn't perform the elements map check.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000260static void GenerateFastArrayLoad(MacroAssembler* masm,
261 Register receiver,
262 Register key,
263 Register elements,
264 Register scratch,
265 Register result,
266 Label* not_fast_array,
267 Label* out_of_range) {
268 // Register use:
269 //
270 // receiver - holds the receiver on entry.
271 // Unchanged unless 'result' is the same register.
272 //
273 // key - holds the smi key on entry.
274 // Unchanged unless 'result' is the same register.
275 //
276 // elements - holds the elements of the receiver on exit.
277 //
278 // result - holds the result on exit if the load succeeded.
279 // Allowed to be the the same as 'receiver' or 'key'.
280 // Unchanged on bailout so 'receiver' and 'key' can be safely
281 // used by further computation.
282 //
283 // Scratch registers:
284 //
285 // scratch - used to hold elements of the receiver and the loaded value.
286
287 __ movq(elements, FieldOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000288 if (not_fast_array != NULL) {
289 // Check that the object is in fast mode and writable.
290 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset),
291 Heap::kFixedArrayMapRootIndex);
292 __ j(not_equal, not_fast_array);
293 } else {
294 __ AssertFastElements(elements);
295 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000296 // Check that the key (index) is within bounds.
297 __ SmiCompare(key, FieldOperand(elements, FixedArray::kLengthOffset));
298 // Unsigned comparison rejects negative indices.
299 __ j(above_equal, out_of_range);
300 // Fast case: Do the load.
301 SmiIndex index = masm->SmiToIndex(scratch, key, kPointerSizeLog2);
302 __ movq(scratch, FieldOperand(elements,
303 index.reg,
304 index.scale,
305 FixedArray::kHeaderSize));
306 __ CompareRoot(scratch, Heap::kTheHoleValueRootIndex);
307 // In case the loaded value is the_hole we have to consult GetProperty
308 // to ensure the prototype chain is searched.
309 __ j(equal, out_of_range);
310 if (!result.is(scratch)) {
311 __ movq(result, scratch);
312 }
313}
314
315
ulan@chromium.org750145a2013-03-07 15:14:13 +0000316// Checks whether a key is an array index string or a unique name.
317// Falls through if the key is a unique name.
318static void GenerateKeyNameCheck(MacroAssembler* masm,
319 Register key,
320 Register map,
321 Register hash,
322 Label* index_string,
323 Label* not_unique) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000324 // Register use:
325 // key - holds the key and is unchanged. Assumed to be non-smi.
326 // Scratch registers:
327 // map - used to hold the map of the key.
328 // hash - used to hold the hash of the key.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000329 Label unique;
330 __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
331 __ j(above, not_unique);
332 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
333 __ j(equal, &unique);
334
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000335 // Is the string an array index, with cached numeric value?
ulan@chromium.org750145a2013-03-07 15:14:13 +0000336 __ movl(hash, FieldOperand(key, Name::kHashFieldOffset));
337 __ testl(hash, Immediate(Name::kContainsCachedArrayIndexMask));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000338 __ j(zero, index_string); // The value in hash is used at jump target.
339
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000340 // Is the string internalized?
341 STATIC_ASSERT(kInternalizedTag != 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000342 __ testb(FieldOperand(map, Map::kInstanceTypeOffset),
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000343 Immediate(kIsInternalizedMask));
ulan@chromium.org750145a2013-03-07 15:14:13 +0000344 __ j(zero, not_unique);
345
346 __ bind(&unique);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000347}
348
349
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000350
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000351void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000352 // ----------- S t a t e -------------
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000353 // -- rax : key
354 // -- rdx : receiver
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000355 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000356 // -----------------------------------
ulan@chromium.org750145a2013-03-07 15:14:13 +0000357 Label slow, check_name, index_smi, index_name, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000358 Label probe_dictionary, check_number_dictionary;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000359
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000360 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000361 __ JumpIfNotSmi(rax, &check_name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000362 __ bind(&index_smi);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000363 // Now the key is known to be a smi. This place is also jumped to from below
364 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000365
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000366 GenerateKeyedLoadReceiverCheck(
367 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
368
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000369 // Check the receiver's map to see if it has fast elements.
370 __ CheckFastElements(rcx, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000371
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000372 GenerateFastArrayLoad(masm,
373 rdx,
374 rax,
375 rcx,
376 rbx,
377 rax,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000378 NULL,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000379 &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000380 Counters* counters = masm->isolate()->counters();
381 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000382 __ ret(0);
383
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000384 __ bind(&check_number_dictionary);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000385 __ SmiToInteger32(rbx, rax);
386 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
387
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000388 // Check whether the elements is a number dictionary.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000389 // rdx: receiver
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000390 // rax: key
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000391 // rbx: key as untagged int32
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000392 // rcx: elements
393 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
394 Heap::kHashTableMapRootIndex);
395 __ j(not_equal, &slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000396 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000397 __ ret(0);
398
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000399 __ bind(&slow);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000400 // Slow case: Jump to runtime.
401 // rdx: receiver
402 // rax: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000403 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000404 GenerateRuntimeGetProperty(masm);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000405
ulan@chromium.org750145a2013-03-07 15:14:13 +0000406 __ bind(&check_name);
407 GenerateKeyNameCheck(masm, rax, rcx, rbx, &index_name, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000408
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000409 GenerateKeyedLoadReceiverCheck(
410 masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
411
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000412 // If the receiver is a fast-case object, check the keyed lookup
413 // cache. Otherwise probe the dictionary leaving result in rcx.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000414 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
415 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
416 Heap::kHashTableMapRootIndex);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000417 __ j(equal, &probe_dictionary);
418
419 // Load the map of the receiver, compute the keyed lookup cache hash
420 // based on 32 bits of the map pointer and the string hash.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000421 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
422 __ movl(rcx, rbx);
423 __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift));
424 __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset));
425 __ shr(rdi, Immediate(String::kHashShift));
426 __ xor_(rcx, rdi);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000427 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
428 __ and_(rcx, Immediate(mask));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000429
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000430 // Load the key (consisting of map and internalized string) from the cache and
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000431 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000432 Label load_in_object_property;
433 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
434 Label hit_on_nth_entry[kEntriesPerBucket];
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000435 ExternalReference cache_keys
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436 = ExternalReference::keyed_lookup_cache_keys(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000437
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000438 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
439 Label try_next_entry;
440 __ movq(rdi, rcx);
441 __ shl(rdi, Immediate(kPointerSizeLog2 + 1));
442 __ LoadAddress(kScratchRegister, cache_keys);
443 int off = kPointerSize * i * 2;
444 __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
445 __ j(not_equal, &try_next_entry);
446 __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
447 __ j(equal, &hit_on_nth_entry[i]);
448 __ bind(&try_next_entry);
449 }
450
451 int off = kPointerSize * (kEntriesPerBucket - 1) * 2;
452 __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000453 __ j(not_equal, &slow);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000454 __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000455 __ j(not_equal, &slow);
456
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000457 // Get field offset, which is a 32-bit integer.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000458 ExternalReference cache_field_offsets
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000460
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000461 // Hit on nth entry.
462 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
463 __ bind(&hit_on_nth_entry[i]);
464 if (i != 0) {
465 __ addl(rcx, Immediate(i));
466 }
467 __ LoadAddress(kScratchRegister, cache_field_offsets);
468 __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0));
469 __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset));
470 __ subq(rdi, rcx);
471 __ j(above_equal, &property_array_property);
472 if (i != 0) {
473 __ jmp(&load_in_object_property);
474 }
475 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000476
477 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000478 __ bind(&load_in_object_property);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000479 __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
480 __ addq(rcx, rdi);
481 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000482 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000483 __ ret(0);
484
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000485 // Load property array property.
486 __ bind(&property_array_property);
487 __ movq(rax, FieldOperand(rdx, JSObject::kPropertiesOffset));
488 __ movq(rax, FieldOperand(rax, rdi, times_pointer_size,
489 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000490 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000491 __ ret(0);
492
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000493 // Do a quick inline probe of the receiver's dictionary, if it
494 // exists.
495 __ bind(&probe_dictionary);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000496 // rdx: receiver
497 // rax: key
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000498 // rbx: elements
499
500 __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
501 __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
502 GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
503
504 GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000505 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000506 __ ret(0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000507
ulan@chromium.org750145a2013-03-07 15:14:13 +0000508 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000509 __ IndexFromHash(rbx, rax);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000510 __ jmp(&index_smi);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000511}
512
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000513
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000514void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
515 // ----------- S t a t e -------------
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000516 // -- rax : key
517 // -- rdx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000518 // -- rsp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000519 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000520 Label miss;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000521
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000522 Register receiver = rdx;
523 Register index = rax;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000524 Register scratch = rcx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000525 Register result = rax;
ager@chromium.org357bf652010-04-12 11:30:10 +0000526
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000527 StringCharAtGenerator char_at_generator(receiver,
528 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000529 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000530 result,
531 &miss, // When not a string.
532 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000533 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000534 STRING_INDEX_IS_ARRAY_INDEX);
535 char_at_generator.GenerateFast(masm);
536 __ ret(0);
ager@chromium.org357bf652010-04-12 11:30:10 +0000537
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000538 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000539 char_at_generator.GenerateSlow(masm, call_helper);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000540
ager@chromium.org357bf652010-04-12 11:30:10 +0000541 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000542 GenerateMiss(masm, MISS);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000543}
544
545
ager@chromium.org5c838252010-02-19 08:53:10 +0000546void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000547 // ----------- S t a t e -------------
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000548 // -- rax : key
549 // -- rdx : receiver
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000550 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000551 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000552 Label slow;
553
ager@chromium.org5c838252010-02-19 08:53:10 +0000554 // Check that the receiver isn't a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000555 __ JumpIfSmi(rdx, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000556
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000557 // Check that the key is an array index, that is Uint32.
558 STATIC_ASSERT(kSmiValueSize <= 32);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000559 __ JumpUnlessNonNegativeSmi(rax, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000560
561 // Get the map of the receiver.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000562 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000563
564 // Check that it has indexed interceptor and access checks
565 // are not enabled for this object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000566 __ movb(rcx, FieldOperand(rcx, Map::kBitFieldOffset));
567 __ andb(rcx, Immediate(kSlowCaseBitFieldMask));
568 __ cmpb(rcx, Immediate(1 << Map::kHasIndexedInterceptor));
ager@chromium.org5c838252010-02-19 08:53:10 +0000569 __ j(not_zero, &slow);
570
571 // Everything is fine, call runtime.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000572 __ pop(rcx);
573 __ push(rdx); // receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000574 __ push(rax); // key
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000575 __ push(rcx); // return address
ager@chromium.org5c838252010-02-19 08:53:10 +0000576
577 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 __ TailCallExternalReference(
579 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
580 masm->isolate()),
581 2,
582 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000583
584 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000585 GenerateMiss(masm, MISS);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000586}
587
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000588
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000589static void KeyedStoreGenerateGenericHelper(
590 MacroAssembler* masm,
591 Label* fast_object,
592 Label* fast_double,
593 Label* slow,
594 KeyedStoreCheckMap check_map,
595 KeyedStoreIncrementLength increment_length) {
596 Label transition_smi_elements;
597 Label finish_object_store, non_double_value, transition_double_elements;
598 Label fast_double_without_map_check;
599 // Fast case: Do the store, could be either Object or double.
600 __ bind(fast_object);
601 // rax: value
602 // rbx: receiver's elements array (a FixedArray)
603 // rcx: index
604 // rdx: receiver (a JSArray)
605 // r9: map of receiver
606 if (check_map == kCheckMap) {
607 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
608 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
609 __ j(not_equal, fast_double);
610 }
611 // Smi stores don't require further checks.
612 Label non_smi_value;
613 __ JumpIfNotSmi(rax, &non_smi_value);
614 if (increment_length == kIncrementLength) {
615 // Add 1 to receiver->length.
616 __ leal(rdi, Operand(rcx, 1));
617 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
618 }
619 // It's irrelevant whether array is smi-only or not when writing a smi.
620 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
621 rax);
622 __ ret(0);
623
624 __ bind(&non_smi_value);
625 // Writing a non-smi, check whether array allows non-smi elements.
626 // r9: receiver's map
627 __ CheckFastObjectElements(r9, &transition_smi_elements);
628
629 __ bind(&finish_object_store);
630 if (increment_length == kIncrementLength) {
631 // Add 1 to receiver->length.
632 __ leal(rdi, Operand(rcx, 1));
633 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
634 }
635 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
636 rax);
637 __ movq(rdx, rax); // Preserve the value which is returned.
638 __ RecordWriteArray(
639 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
640 __ ret(0);
641
642 __ bind(fast_double);
643 if (check_map == kCheckMap) {
644 // Check for fast double array case. If this fails, call through to the
645 // runtime.
646 // rdi: elements array's map
647 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
648 __ j(not_equal, slow);
649 }
650 __ bind(&fast_double_without_map_check);
651 __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
652 &transition_double_elements);
653 if (increment_length == kIncrementLength) {
654 // Add 1 to receiver->length.
655 __ leal(rdi, Operand(rcx, 1));
656 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
657 }
658 __ ret(0);
659
660 __ bind(&transition_smi_elements);
661 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
662
663 // Transition the array appropriately depending on the value type.
664 __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
665 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
666 __ j(not_equal, &non_double_value);
667
668 // Value is a double. Transition FAST_SMI_ELEMENTS ->
669 // FAST_DOUBLE_ELEMENTS and complete the store.
670 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
671 FAST_DOUBLE_ELEMENTS,
672 rbx,
673 rdi,
674 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000675 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
676 FAST_DOUBLE_ELEMENTS);
677 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000678 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
679 __ jmp(&fast_double_without_map_check);
680
681 __ bind(&non_double_value);
682 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
683 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
684 FAST_ELEMENTS,
685 rbx,
686 rdi,
687 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000688 mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
689 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
690 slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000691 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
692 __ jmp(&finish_object_store);
693
694 __ bind(&transition_double_elements);
695 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
696 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
697 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
698 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
699 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
700 FAST_ELEMENTS,
701 rbx,
702 rdi,
703 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000704 mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
705 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000706 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
707 __ jmp(&finish_object_store);
708}
709
710
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000711void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
712 StrictModeFlag strict_mode) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000713 // ----------- S t a t e -------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000714 // -- rax : value
715 // -- rcx : key
716 // -- rdx : receiver
717 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000718 // -----------------------------------
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000719 Label slow, slow_with_tagged_index, fast_object, fast_object_grow;
720 Label fast_double, fast_double_grow;
721 Label array, extra, check_if_double_array;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000722
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000723 // Check that the object isn't a smi.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000724 __ JumpIfSmi(rdx, &slow_with_tagged_index);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000725 // Get the map from the receiver.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000726 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000727 // Check that the receiver does not require access checks. We need
728 // to do this because this generic stub does not perform map checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000729 __ testb(FieldOperand(r9, Map::kBitFieldOffset),
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000730 Immediate(1 << Map::kIsAccessCheckNeeded));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000731 __ j(not_zero, &slow_with_tagged_index);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000732 // Check that the key is a smi.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000733 __ JumpIfNotSmi(rcx, &slow_with_tagged_index);
734 __ SmiToInteger32(rcx, rcx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000735
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000736 __ CmpInstanceType(r9, JS_ARRAY_TYPE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000737 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000738 // Check that the object is some kind of JSObject.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000739 __ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000740 __ j(below, &slow);
741
742 // Object case: Check key against length in the elements array.
743 // rax: value
744 // rdx: JSObject
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000745 // rcx: index
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000746 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000747 // Check array bounds.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000748 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000749 // rax: value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000750 // rbx: FixedArray
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000751 // rcx: index
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000752 __ j(above, &fast_object);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000753
ager@chromium.org3811b432009-10-28 14:53:37 +0000754 // Slow case: call runtime.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000755 __ bind(&slow);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000756 __ Integer32ToSmi(rcx, rcx);
757 __ bind(&slow_with_tagged_index);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000758 GenerateRuntimeSetProperty(masm, strict_mode);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000759 // Never returns to here.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000760
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000761 // Extra capacity case: Check if there is extra capacity to
762 // perform the store and update the length. Used for adding one
763 // element to the array by writing to array[array.length].
764 __ bind(&extra);
765 // rax: value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000766 // rdx: receiver (a JSArray)
767 // rbx: receiver's elements array (a FixedArray)
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000768 // rcx: index
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000769 // flags: smicompare (rdx.length(), rbx)
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000770 __ j(not_equal, &slow); // do not leave holes in the array
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000771 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
772 __ j(below_equal, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000773 // Increment index to get new length.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000774 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
775 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000776 __ j(not_equal, &check_if_double_array);
777 __ jmp(&fast_object_grow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000778
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000779 __ bind(&check_if_double_array);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000780 // rdi: elements array's map
781 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
782 __ j(not_equal, &slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000783 __ jmp(&fast_double_grow);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000784
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000785 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000786 // array. Check that the array is in fast mode (and writable); if it
787 // is the length is always a smi.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000788 __ bind(&array);
789 // rax: value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000790 // rdx: receiver (a JSArray)
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000791 // rcx: index
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000792 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000793
794 // Check the key against the length in the array, compute the
795 // address to store into and fall through to fast case.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000796 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000797 __ j(below_equal, &extra);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000798
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000799 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
800 &slow, kCheckMap, kDontIncrementLength);
801 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
802 &slow, kDontCheckMap, kIncrementLength);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000803}
804
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000805
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000806// The generated code does not accept smi keys.
807// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000808void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
809 int argc,
810 Code::Kind kind,
811 Code::ExtraICState extra_state) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000812 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000813 // rcx : function name
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000814 // rdx : receiver
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000815 // -----------------------------------
816 Label number, non_number, non_string, boolean, probe, miss;
817
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000818 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000819 Code::Flags flags = Code::ComputeFlags(kind,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000820 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000821 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000822 Code::NORMAL,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000823 argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
825 rax);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000826
827 // If the stub cache probing failed, the receiver might be a value.
828 // For value objects, we use the map of the prototype objects for
829 // the corresponding JSValue for the cache and that is what we need
830 // to probe.
831 //
832 // Check for number.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000833 __ JumpIfSmi(rdx, &number);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000834 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx);
835 __ j(not_equal, &non_number);
836 __ bind(&number);
837 StubCompiler::GenerateLoadGlobalFunctionPrototype(
838 masm, Context::NUMBER_FUNCTION_INDEX, rdx);
839 __ jmp(&probe);
840
841 // Check for string.
842 __ bind(&non_number);
843 __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE);
844 __ j(above_equal, &non_string);
845 StubCompiler::GenerateLoadGlobalFunctionPrototype(
846 masm, Context::STRING_FUNCTION_INDEX, rdx);
847 __ jmp(&probe);
848
849 // Check for boolean.
850 __ bind(&non_string);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000851 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000852 __ j(equal, &boolean);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000853 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000854 __ j(not_equal, &miss);
855 __ bind(&boolean);
856 StubCompiler::GenerateLoadGlobalFunctionPrototype(
857 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx);
858
859 // Probe the stub cache for the value object.
860 __ bind(&probe);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
862 no_reg);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000863
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000864 __ bind(&miss);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000865}
866
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000867
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000868static void GenerateFunctionTailCall(MacroAssembler* masm,
869 int argc,
870 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000871 // ----------- S t a t e -------------
872 // rcx : function name
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000873 // rdi : function
ager@chromium.org5c838252010-02-19 08:53:10 +0000874 // rsp[0] : return address
875 // rsp[8] : argument argc
876 // rsp[16] : argument argc - 1
877 // ...
878 // rsp[argc * 8] : argument 1
879 // rsp[(argc + 1) * 8] : argument 0 = receiver
880 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000881 __ JumpIfSmi(rdi, miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000882 // Check that the value is a JavaScript function.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000883 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000884 __ j(not_equal, miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000885
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000886 // Invoke the function.
887 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000888 __ InvokeFunction(rdi, actual, JUMP_FUNCTION,
889 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000890}
891
892
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000893// The generated code falls through if the call should be handled by runtime.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000894void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000895 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000896 // rcx : function name
897 // rsp[0] : return address
898 // rsp[8] : argument argc
899 // rsp[16] : argument argc - 1
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000900 // ...
ager@chromium.org5c838252010-02-19 08:53:10 +0000901 // rsp[argc * 8] : argument 1
902 // rsp[(argc + 1) * 8] : argument 0 = receiver
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000903 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000904 Label miss;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000905
906 // Get the receiver of the function from the stack.
907 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000908
ulan@chromium.org750145a2013-03-07 15:14:13 +0000909 GenerateNameDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000910
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000911 // rax: elements
912 // Search the dictionary placing the result in rdi.
913 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000914
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000915 GenerateFunctionTailCall(masm, argc, &miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000916
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000917 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000918}
919
920
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000921void CallICBase::GenerateMiss(MacroAssembler* masm,
922 int argc,
923 IC::UtilityId id,
924 Code::ExtraICState extra_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000925 // ----------- S t a t e -------------
926 // rcx : function name
927 // rsp[0] : return address
928 // rsp[8] : argument argc
929 // rsp[16] : argument argc - 1
930 // ...
931 // rsp[argc * 8] : argument 1
932 // rsp[(argc + 1) * 8] : argument 0 = receiver
933 // -----------------------------------
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000934
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000935 Counters* counters = masm->isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000936 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000937 __ IncrementCounter(counters->call_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000938 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000939 __ IncrementCounter(counters->keyed_call_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000940 }
941
942 // Get the receiver of the function from the stack; 1 ~ return address.
943 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
944
945 // Enter an internal frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000946 {
947 FrameScope scope(masm, StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000948
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000949 // Push the receiver and the name of the function.
950 __ push(rdx);
951 __ push(rcx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000952
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000953 // Call the entry.
954 CEntryStub stub(1);
955 __ Set(rax, 2);
956 __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
957 __ CallStub(&stub);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000958
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000959 // Move result to rdi and exit the internal frame.
960 __ movq(rdi, rax);
961 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000962
963 // Check if the receiver is a global object of some sort.
964 // This can happen only for regular CallIC but not KeyedCallIC.
965 if (id == IC::kCallIC_Miss) {
966 Label invoke, global;
967 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); // receiver
968 __ JumpIfSmi(rdx, &invoke);
969 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
970 __ j(equal, &global);
971 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
972 __ j(not_equal, &invoke);
973
974 // Patch the receiver on the stack.
975 __ bind(&global);
976 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
977 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
978 __ bind(&invoke);
979 }
980
981 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000982 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +0000983 ? CALL_AS_FUNCTION
984 : CALL_AS_METHOD;
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000985 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000986 __ InvokeFunction(rdi,
987 actual,
988 JUMP_FUNCTION,
989 NullCallWrapper(),
990 call_kind);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000991}
992
993
danno@chromium.org40cb8782011-05-25 07:58:50 +0000994void CallIC::GenerateMegamorphic(MacroAssembler* masm,
995 int argc,
996 Code::ExtraICState extra_ic_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000997 // ----------- S t a t e -------------
998 // rcx : function name
999 // rsp[0] : return address
1000 // rsp[8] : argument argc
1001 // rsp[16] : argument argc - 1
1002 // ...
1003 // rsp[argc * 8] : argument 1
1004 // rsp[(argc + 1) * 8] : argument 0 = receiver
1005 // -----------------------------------
1006
1007 // Get the receiver of the function from the stack; 1 ~ return address.
1008 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001009 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
1010 GenerateMiss(masm, argc, extra_ic_state);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001011}
1012
1013
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001014void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001015 // ----------- S t a t e -------------
1016 // rcx : function name
1017 // rsp[0] : return address
1018 // rsp[8] : argument argc
1019 // rsp[16] : argument argc - 1
1020 // ...
1021 // rsp[argc * 8] : argument 1
1022 // rsp[(argc + 1) * 8] : argument 0 = receiver
1023 // -----------------------------------
1024
1025 // Get the receiver of the function from the stack; 1 ~ return address.
1026 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1027
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001028 Label do_call, slow_call, slow_load;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001029 Label check_number_dictionary, check_name, lookup_monomorphic_cache;
1030 Label index_smi, index_name;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001031
1032 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001033 __ JumpIfNotSmi(rcx, &check_name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001034
1035 __ bind(&index_smi);
1036 // Now the key is known to be a smi. This place is also jumped to from below
1037 // where a numeric string is converted to a smi.
1038
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001039 GenerateKeyedLoadReceiverCheck(
1040 masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001041
1042 GenerateFastArrayLoad(
1043 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001044 Counters* counters = masm->isolate()->counters();
1045 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001046
1047 __ bind(&do_call);
1048 // receiver in rdx is not used after this point.
1049 // rcx: key
1050 // rdi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001051 GenerateFunctionTailCall(masm, argc, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001052
1053 __ bind(&check_number_dictionary);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001054 // rax: elements
1055 // rcx: smi key
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001056 // Check whether the elements is a number dictionary.
1057 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1058 Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001059 __ j(not_equal, &slow_load);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001060 __ SmiToInteger32(rbx, rcx);
1061 // ebx: untagged index
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001062 __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001063 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001064 __ jmp(&do_call);
1065
1066 __ bind(&slow_load);
1067 // This branch is taken when calling KeyedCallIC_Miss is neither required
1068 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001069 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001070 {
1071 FrameScope scope(masm, StackFrame::INTERNAL);
1072 __ push(rcx); // save the key
1073 __ push(rdx); // pass the receiver
1074 __ push(rcx); // pass the key
1075 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1076 __ pop(rcx); // restore the key
1077 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001078 __ movq(rdi, rax);
1079 __ jmp(&do_call);
1080
ulan@chromium.org750145a2013-03-07 15:14:13 +00001081 __ bind(&check_name);
1082 GenerateKeyNameCheck(masm, rcx, rax, rbx, &index_name, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001083
ulan@chromium.org750145a2013-03-07 15:14:13 +00001084 // The key is known to be a unique name.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001085 // If the receiver is a regular JS object with slow properties then do
1086 // a quick inline probe of the receiver's dictionary.
1087 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001088 GenerateKeyedLoadReceiverCheck(
1089 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001090
1091 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
1092 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1093 Heap::kHashTableMapRootIndex);
1094 __ j(not_equal, &lookup_monomorphic_cache);
1095
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001096 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001097 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001098 __ jmp(&do_call);
1099
1100 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001101 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001102 GenerateMonomorphicCacheProbe(masm,
1103 argc,
1104 Code::KEYED_CALL_IC,
1105 Code::kNoExtraICState);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001106 // Fall through on miss.
1107
1108 __ bind(&slow_call);
1109 // This branch is taken if:
1110 // - the receiver requires boxing or access check,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001111 // - the key is neither smi nor a unique name,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001112 // - the value loaded is not a function,
1113 // - there is hope that the runtime will create a monomorphic call stub
1114 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001115 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001116 GenerateMiss(masm, argc);
1117
ulan@chromium.org750145a2013-03-07 15:14:13 +00001118 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001119 __ IndexFromHash(rbx, rcx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001120 // Now jump to the place where smi keys are handled.
1121 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001122}
1123
1124
1125void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001126 // ----------- S t a t e -------------
1127 // rcx : function name
1128 // rsp[0] : return address
1129 // rsp[8] : argument argc
1130 // rsp[16] : argument argc - 1
1131 // ...
1132 // rsp[argc * 8] : argument 1
1133 // rsp[(argc + 1) * 8] : argument 0 = receiver
1134 // -----------------------------------
1135
ulan@chromium.org750145a2013-03-07 15:14:13 +00001136 // Check if the name is really a name.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001137 Label miss;
1138 __ JumpIfSmi(rcx, &miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001139 Condition cond = masm->IsObjectNameType(rcx, rax, rax);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001140 __ j(NegateCondition(cond), &miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001141 CallICBase::GenerateNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001142 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001143 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001144}
1145
1146
whesse@chromium.org7b260152011-06-20 15:33:18 +00001147static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
1148 Register object,
1149 Register key,
1150 Register scratch1,
1151 Register scratch2,
1152 Register scratch3,
1153 Label* unmapped_case,
1154 Label* slow_case) {
1155 Heap* heap = masm->isolate()->heap();
1156
ager@chromium.org04921a82011-06-27 13:21:41 +00001157 // Check that the receiver is a JSObject. Because of the elements
1158 // map check later, we do not need to check for interceptors or
1159 // whether it requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001160 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +00001161 // Check that the object is some kind of JSObject.
1162 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
1163 __ j(below, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001164
1165 // Check that the key is a positive smi.
1166 Condition check = masm->CheckNonNegativeSmi(key);
1167 __ j(NegateCondition(check), slow_case);
1168
1169 // Load the elements into scratch1 and check its map. If not, jump
1170 // to the unmapped lookup with the parameter map in scratch1.
1171 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
1172 __ movq(scratch1, FieldOperand(object, JSObject::kElementsOffset));
1173 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
1174
1175 // Check if element is in the range of mapped arguments.
1176 __ movq(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
1177 __ SmiSubConstant(scratch2, scratch2, Smi::FromInt(2));
1178 __ cmpq(key, scratch2);
1179 __ j(greater_equal, unmapped_case);
1180
1181 // Load element index and check whether it is the hole.
1182 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
1183 __ SmiToInteger64(scratch3, key);
1184 __ movq(scratch2, FieldOperand(scratch1,
1185 scratch3,
1186 times_pointer_size,
1187 kHeaderSize));
1188 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex);
1189 __ j(equal, unmapped_case);
1190
1191 // Load value from context and return it. We can reuse scratch1 because
1192 // we do not jump to the unmapped lookup (which requires the parameter
1193 // map in scratch1).
1194 __ movq(scratch1, FieldOperand(scratch1, FixedArray::kHeaderSize));
1195 __ SmiToInteger64(scratch3, scratch2);
1196 return FieldOperand(scratch1,
1197 scratch3,
1198 times_pointer_size,
1199 Context::kHeaderSize);
1200}
1201
1202
1203static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
1204 Register key,
1205 Register parameter_map,
1206 Register scratch,
1207 Label* slow_case) {
1208 // Element is in arguments backing store, which is referenced by the
1209 // second element of the parameter_map. The parameter_map register
1210 // must be loaded with the parameter map of the arguments object and is
1211 // overwritten.
1212 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
1213 Register backing_store = parameter_map;
1214 __ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001215 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
1216 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001217 __ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
1218 __ cmpq(key, scratch);
1219 __ j(greater_equal, slow_case);
1220 __ SmiToInteger64(scratch, key);
1221 return FieldOperand(backing_store,
1222 scratch,
1223 times_pointer_size,
1224 FixedArray::kHeaderSize);
1225}
1226
1227
1228void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1229 // ----------- S t a t e -------------
1230 // -- rax : key
1231 // -- rdx : receiver
1232 // -- rsp[0] : return address
1233 // -----------------------------------
1234 Label slow, notin;
1235 Operand mapped_location =
1236 GenerateMappedArgumentsLookup(
1237 masm, rdx, rax, rbx, rcx, rdi, &notin, &slow);
1238 __ movq(rax, mapped_location);
1239 __ Ret();
1240 __ bind(&notin);
1241 // The unmapped lookup expects that the parameter map is in rbx.
1242 Operand unmapped_location =
1243 GenerateUnmappedArgumentsLookup(masm, rax, rbx, rcx, &slow);
1244 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1245 __ j(equal, &slow);
1246 __ movq(rax, unmapped_location);
1247 __ Ret();
1248 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001249 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001250}
1251
1252
1253void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1254 // ----------- S t a t e -------------
1255 // -- rax : value
1256 // -- rcx : key
1257 // -- rdx : receiver
1258 // -- rsp[0] : return address
1259 // -----------------------------------
1260 Label slow, notin;
1261 Operand mapped_location = GenerateMappedArgumentsLookup(
1262 masm, rdx, rcx, rbx, rdi, r8, &notin, &slow);
1263 __ movq(mapped_location, rax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +00001264 __ lea(r9, mapped_location);
1265 __ movq(r8, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001266 __ RecordWrite(rbx,
1267 r9,
1268 r8,
1269 kDontSaveFPRegs,
1270 EMIT_REMEMBERED_SET,
1271 INLINE_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001272 __ Ret();
1273 __ bind(&notin);
1274 // The unmapped lookup expects that the parameter map is in rbx.
1275 Operand unmapped_location =
1276 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow);
1277 __ movq(unmapped_location, rax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +00001278 __ lea(r9, unmapped_location);
1279 __ movq(r8, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 __ RecordWrite(rbx,
1281 r9,
1282 r8,
1283 kDontSaveFPRegs,
1284 EMIT_REMEMBERED_SET,
1285 INLINE_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001286 __ Ret();
1287 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001288 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001289}
1290
1291
1292void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1293 int argc) {
1294 // ----------- S t a t e -------------
1295 // rcx : function name
1296 // rsp[0] : return address
1297 // rsp[8] : argument argc
1298 // rsp[16] : argument argc - 1
1299 // ...
1300 // rsp[argc * 8] : argument 1
1301 // rsp[(argc + 1) * 8] : argument 0 = receiver
1302 // -----------------------------------
1303 Label slow, notin;
1304 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
1305 Operand mapped_location = GenerateMappedArgumentsLookup(
1306 masm, rdx, rcx, rbx, rax, r8, &notin, &slow);
1307 __ movq(rdi, mapped_location);
1308 GenerateFunctionTailCall(masm, argc, &slow);
1309 __ bind(&notin);
1310 // The unmapped lookup expects that the parameter map is in rbx.
1311 Operand unmapped_location =
1312 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rax, &slow);
1313 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1314 __ j(equal, &slow);
1315 __ movq(rdi, unmapped_location);
1316 GenerateFunctionTailCall(masm, argc, &slow);
1317 __ bind(&slow);
1318 GenerateMiss(masm, argc);
1319}
1320
1321
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001322void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001323 // ----------- S t a t e -------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001324 // -- rax : receiver
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001325 // -- rcx : name
1326 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001327 // -----------------------------------
1328
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001329 // Probe the stub cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001330 Code::Flags flags = Code::ComputeFlags(
ulan@chromium.org750145a2013-03-07 15:14:13 +00001331 Code::STUB, MONOMORPHIC, Code::kNoExtraICState,
1332 Code::NORMAL, Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001333 Isolate::Current()->stub_cache()->GenerateProbe(
1334 masm, flags, rax, rcx, rbx, rdx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001335
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001336 GenerateMiss(masm);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001337}
1338
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001339
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001340void LoadIC::GenerateNormal(MacroAssembler* masm) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001341 // ----------- S t a t e -------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001342 // -- rax : receiver
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001343 // -- rcx : name
1344 // -- rsp[0] : return address
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001345 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001346 Label miss;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001347
ulan@chromium.org750145a2013-03-07 15:14:13 +00001348 GenerateNameDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001349
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001350 // rdx: elements
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001351 // Search the dictionary placing the result in rax.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001352 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001353 __ ret(0);
1354
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001355 // Cache miss: Jump to runtime.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001356 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001357 GenerateMiss(masm);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001358}
1359
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001360
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001361void LoadIC::GenerateMiss(MacroAssembler* masm) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001362 // ----------- S t a t e -------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001363 // -- rax : receiver
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001364 // -- rcx : name
1365 // -- rsp[0] : return address
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001366 // -----------------------------------
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001367
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001368 Counters* counters = masm->isolate()->counters();
1369 __ IncrementCounter(counters->load_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001370
1371 __ pop(rbx);
1372 __ push(rax); // receiver
1373 __ push(rcx); // name
1374 __ push(rbx); // return address
1375
1376 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001377 ExternalReference ref =
1378 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001379 __ TailCallExternalReference(ref, 2, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001380}
1381
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001382
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001383void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001384 // ----------- S t a t e -------------
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001385 // -- rax : key
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001386 // -- rdx : receiver
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001387 // -- rsp[0] : return address
1388 // -----------------------------------
1389
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001390 Counters* counters = masm->isolate()->counters();
1391 __ IncrementCounter(counters->keyed_load_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001392
1393 __ pop(rbx);
1394 __ push(rdx); // receiver
1395 __ push(rax); // name
1396 __ push(rbx); // return address
1397
1398 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001399 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001400 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1401 masm->isolate())
1402 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001403 __ TailCallExternalReference(ref, 2, 1);
1404}
1405
1406
1407void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1408 // ----------- S t a t e -------------
1409 // -- rax : key
1410 // -- rdx : receiver
1411 // -- rsp[0] : return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001412 // -----------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001413
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001414 __ pop(rbx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001415 __ push(rdx); // receiver
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001416 __ push(rax); // name
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001417 __ push(rbx); // return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001418
1419 // Perform tail call to the entry.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001420 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001421}
1422
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001423
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001424void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001425 StrictModeFlag strict_mode) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001426 // ----------- S t a t e -------------
1427 // -- rax : value
1428 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001429 // -- rdx : receiver
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001430 // -- rsp[0] : return address
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001431 // -----------------------------------
1432
1433 // Get the receiver from the stack and probe the stub cache.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001434 Code::Flags flags =
1435 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
1437 no_reg);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001438
1439 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001440 GenerateMiss(masm);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001441}
1442
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001443
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001444void StoreIC::GenerateMiss(MacroAssembler* masm) {
1445 // ----------- S t a t e -------------
1446 // -- rax : value
1447 // -- rcx : name
1448 // -- rdx : receiver
1449 // -- rsp[0] : return address
1450 // -----------------------------------
1451
1452 __ pop(rbx);
1453 __ push(rdx); // receiver
1454 __ push(rcx); // name
1455 __ push(rax); // value
1456 __ push(rbx); // return address
1457
1458 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 ExternalReference ref =
1460 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001461 __ TailCallExternalReference(ref, 3, 1);
1462}
1463
1464
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001465void StoreIC::GenerateNormal(MacroAssembler* masm) {
1466 // ----------- S t a t e -------------
1467 // -- rax : value
1468 // -- rcx : name
1469 // -- rdx : receiver
1470 // -- rsp[0] : return address
1471 // -----------------------------------
1472
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001473 Label miss;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001474
ulan@chromium.org750145a2013-03-07 15:14:13 +00001475 GenerateNameDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001476
1477 GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001478 Counters* counters = masm->isolate()->counters();
1479 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001480 __ ret(0);
1481
1482 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001483 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001484 GenerateMiss(masm);
1485}
1486
1487
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001488void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1489 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001490 // ----------- S t a t e -------------
1491 // -- rax : value
1492 // -- rcx : name
1493 // -- rdx : receiver
1494 // -- rsp[0] : return address
1495 // -----------------------------------
1496 __ pop(rbx);
1497 __ push(rdx);
1498 __ push(rcx);
1499 __ push(rax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001500 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1501 __ Push(Smi::FromInt(strict_mode));
1502 __ push(rbx); // return address
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001503
1504 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001505 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001506}
1507
1508
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001509void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1510 StrictModeFlag strict_mode) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001511 // ----------- S t a t e -------------
1512 // -- rax : value
1513 // -- rcx : key
1514 // -- rdx : receiver
1515 // -- rsp[0] : return address
1516 // -----------------------------------
1517
1518 __ pop(rbx);
1519 __ push(rdx); // receiver
1520 __ push(rcx); // key
1521 __ push(rax); // value
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001522 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1523 __ Push(Smi::FromInt(strict_mode)); // Strict mode.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001524 __ push(rbx); // return address
1525
1526 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001528}
1529
1530
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001531void StoreIC::GenerateSlow(MacroAssembler* masm) {
1532 // ----------- S t a t e -------------
1533 // -- rax : value
1534 // -- rcx : key
1535 // -- rdx : receiver
1536 // -- rsp[0] : return address
1537 // -----------------------------------
1538
1539 __ pop(rbx);
1540 __ push(rdx); // receiver
1541 __ push(rcx); // key
1542 __ push(rax); // value
1543 __ push(rbx); // return address
1544
1545 // Do tail-call to runtime routine.
1546 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1547 __ TailCallExternalReference(ref, 3, 1);
1548}
1549
1550
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001551void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001552 // ----------- S t a t e -------------
1553 // -- rax : value
1554 // -- rcx : key
1555 // -- rdx : receiver
1556 // -- rsp[0] : return address
1557 // -----------------------------------
1558
1559 __ pop(rbx);
1560 __ push(rdx); // receiver
1561 __ push(rcx); // key
1562 __ push(rax); // value
1563 __ push(rbx); // return address
1564
1565 // Do tail-call to runtime routine.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001566 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1567 __ TailCallExternalReference(ref, 3, 1);
1568}
1569
1570
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001571void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001572 // ----------- S t a t e -------------
1573 // -- rax : value
1574 // -- rcx : key
1575 // -- rdx : receiver
1576 // -- rsp[0] : return address
1577 // -----------------------------------
1578
1579 __ pop(rbx);
1580 __ push(rdx); // receiver
1581 __ push(rcx); // key
1582 __ push(rax); // value
1583 __ push(rbx); // return address
1584
1585 // Do tail-call to runtime routine.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001586 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001587 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1588 masm->isolate())
1589 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001590 __ TailCallExternalReference(ref, 3, 1);
1591}
1592
1593
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001594void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1595 // ----------- S t a t e -------------
1596 // -- rbx : target map
1597 // -- rdx : receiver
1598 // -- rsp[0] : return address
1599 // -----------------------------------
1600 // Must return the modified receiver in eax.
1601 if (!FLAG_trace_elements_transitions) {
1602 Label fail;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001603 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1604 FAST_DOUBLE_ELEMENTS);
1605 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001606 __ movq(rax, rdx);
1607 __ Ret();
1608 __ bind(&fail);
1609 }
1610
1611 __ pop(rbx);
1612 __ push(rdx);
1613 __ push(rbx); // return address
1614 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1615}
1616
1617
1618void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1619 MacroAssembler* masm) {
1620 // ----------- S t a t e -------------
1621 // -- rbx : target map
1622 // -- rdx : receiver
1623 // -- rsp[0] : return address
1624 // -----------------------------------
1625 // Must return the modified receiver in eax.
1626 if (!FLAG_trace_elements_transitions) {
1627 Label fail;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001628 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
1629 FAST_ELEMENTS);
1630 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001631 __ movq(rax, rdx);
1632 __ Ret();
1633 __ bind(&fail);
1634 }
1635
1636 __ pop(rbx);
1637 __ push(rdx);
1638 __ push(rbx); // return address
1639 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1640}
1641
1642
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001643#undef __
1644
1645
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001646Condition CompareIC::ComputeCondition(Token::Value op) {
1647 switch (op) {
1648 case Token::EQ_STRICT:
1649 case Token::EQ:
1650 return equal;
1651 case Token::LT:
1652 return less;
1653 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001654 return greater;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001655 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001656 return less_equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001657 case Token::GTE:
1658 return greater_equal;
1659 default:
1660 UNREACHABLE();
1661 return no_condition;
1662 }
1663}
1664
1665
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001666bool CompareIC::HasInlinedSmiCode(Address address) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001667 // The address of the instruction following the call.
1668 Address test_instruction_address =
1669 address + Assembler::kCallTargetAddressOffset;
1670
1671 // If the instruction following the call is not a test al, nothing
1672 // was inlined.
1673 return *test_instruction_address == Assembler::kTestAlByte;
1674}
1675
1676
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001677void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001678 // The address of the instruction following the call.
1679 Address test_instruction_address =
1680 address + Assembler::kCallTargetAddressOffset;
1681
1682 // If the instruction following the call is not a test al, nothing
1683 // was inlined.
1684 if (*test_instruction_address != Assembler::kTestAlByte) {
1685 ASSERT(*test_instruction_address == Assembler::kNopByte);
1686 return;
1687 }
1688
1689 Address delta_address = test_instruction_address + 1;
1690 // The delta to the start of the map check instruction and the
1691 // condition code uses at the patched jump.
1692 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1693 if (FLAG_trace_ic) {
1694 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1695 address, test_instruction_address, delta);
1696 }
1697
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001698 // Patch with a short conditional jump. Enabling means switching from a short
1699 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
1700 // reverse operation of that.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001701 Address jmp_address = test_instruction_address - delta;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001702 ASSERT((check == ENABLE_INLINED_SMI_CHECK)
1703 ? (*jmp_address == Assembler::kJncShortOpcode ||
1704 *jmp_address == Assembler::kJcShortOpcode)
1705 : (*jmp_address == Assembler::kJnzShortOpcode ||
1706 *jmp_address == Assembler::kJzShortOpcode));
1707 Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1708 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1709 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001710 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001711}
1712
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001713
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001714} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001715
1716#endif // V8_TARGET_ARCH_X64