blob: fe8734caf47988adfa4c2ddb1c10c4b44e1af6b9 [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
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_X64
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
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
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000340 // Is the string internalized? We already know it's a string so a single
341 // bit test is enough.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000342 STATIC_ASSERT(kNotInternalizedTag != 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000343 __ testb(FieldOperand(map, Map::kInstanceTypeOffset),
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000344 Immediate(kIsNotInternalizedMask));
345 __ j(not_zero, not_unique);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000346
347 __ bind(&unique);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000348}
349
350
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000351
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000352void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000353 // ----------- S t a t e -------------
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000354 // -- rax : key
355 // -- rdx : receiver
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000356 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000357 // -----------------------------------
ulan@chromium.org750145a2013-03-07 15:14:13 +0000358 Label slow, check_name, index_smi, index_name, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000359 Label probe_dictionary, check_number_dictionary;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000360
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000361 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000362 __ JumpIfNotSmi(rax, &check_name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000363 __ bind(&index_smi);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000364 // Now the key is known to be a smi. This place is also jumped to from below
365 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000366
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000367 GenerateKeyedLoadReceiverCheck(
368 masm, rdx, rcx, Map::kHasIndexedInterceptor, &slow);
369
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000370 // Check the receiver's map to see if it has fast elements.
371 __ CheckFastElements(rcx, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000372
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000373 GenerateFastArrayLoad(masm,
374 rdx,
375 rax,
376 rcx,
377 rbx,
378 rax,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000379 NULL,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000380 &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000381 Counters* counters = masm->isolate()->counters();
382 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000383 __ ret(0);
384
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000385 __ bind(&check_number_dictionary);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000386 __ SmiToInteger32(rbx, rax);
387 __ movq(rcx, FieldOperand(rdx, JSObject::kElementsOffset));
388
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000389 // Check whether the elements is a number dictionary.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000390 // rdx: receiver
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000391 // rax: key
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000392 // rbx: key as untagged int32
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000393 // rcx: elements
394 __ CompareRoot(FieldOperand(rcx, HeapObject::kMapOffset),
395 Heap::kHashTableMapRootIndex);
396 __ j(not_equal, &slow);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000397 __ LoadFromNumberDictionary(&slow, rcx, rax, rbx, r9, rdi, rax);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000398 __ ret(0);
399
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000400 __ bind(&slow);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000401 // Slow case: Jump to runtime.
402 // rdx: receiver
403 // rax: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000404 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000405 GenerateRuntimeGetProperty(masm);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000406
ulan@chromium.org750145a2013-03-07 15:14:13 +0000407 __ bind(&check_name);
408 GenerateKeyNameCheck(masm, rax, rcx, rbx, &index_name, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000409
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000410 GenerateKeyedLoadReceiverCheck(
411 masm, rdx, rcx, Map::kHasNamedInterceptor, &slow);
412
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000413 // If the receiver is a fast-case object, check the keyed lookup
414 // cache. Otherwise probe the dictionary leaving result in rcx.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000415 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
416 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
417 Heap::kHashTableMapRootIndex);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000418 __ j(equal, &probe_dictionary);
419
420 // Load the map of the receiver, compute the keyed lookup cache hash
421 // based on 32 bits of the map pointer and the string hash.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000422 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
423 __ movl(rcx, rbx);
424 __ shr(rcx, Immediate(KeyedLookupCache::kMapHashShift));
425 __ movl(rdi, FieldOperand(rax, String::kHashFieldOffset));
426 __ shr(rdi, Immediate(String::kHashShift));
427 __ xor_(rcx, rdi);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000428 int mask = (KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
429 __ and_(rcx, Immediate(mask));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000430
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000431 // Load the key (consisting of map and internalized string) from the cache and
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000432 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000433 Label load_in_object_property;
434 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
435 Label hit_on_nth_entry[kEntriesPerBucket];
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000436 ExternalReference cache_keys
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000437 = ExternalReference::keyed_lookup_cache_keys(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000438
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000439 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
440 Label try_next_entry;
441 __ movq(rdi, rcx);
442 __ shl(rdi, Immediate(kPointerSizeLog2 + 1));
443 __ LoadAddress(kScratchRegister, cache_keys);
444 int off = kPointerSize * i * 2;
445 __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
446 __ j(not_equal, &try_next_entry);
447 __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
448 __ j(equal, &hit_on_nth_entry[i]);
449 __ bind(&try_next_entry);
450 }
451
452 int off = kPointerSize * (kEntriesPerBucket - 1) * 2;
453 __ cmpq(rbx, Operand(kScratchRegister, rdi, times_1, off));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000454 __ j(not_equal, &slow);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000455 __ cmpq(rax, Operand(kScratchRegister, rdi, times_1, off + kPointerSize));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000456 __ j(not_equal, &slow);
457
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000458 // Get field offset, which is a 32-bit integer.
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000459 ExternalReference cache_field_offsets
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000460 = ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000461
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000462 // Hit on nth entry.
463 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
464 __ bind(&hit_on_nth_entry[i]);
465 if (i != 0) {
466 __ addl(rcx, Immediate(i));
467 }
468 __ LoadAddress(kScratchRegister, cache_field_offsets);
469 __ movl(rdi, Operand(kScratchRegister, rcx, times_4, 0));
470 __ movzxbq(rcx, FieldOperand(rbx, Map::kInObjectPropertiesOffset));
471 __ subq(rdi, rcx);
472 __ j(above_equal, &property_array_property);
473 if (i != 0) {
474 __ jmp(&load_in_object_property);
475 }
476 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000477
478 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000479 __ bind(&load_in_object_property);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000480 __ movzxbq(rcx, FieldOperand(rbx, Map::kInstanceSizeOffset));
481 __ addq(rcx, rdi);
482 __ movq(rax, FieldOperand(rdx, rcx, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000483 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000484 __ ret(0);
485
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000486 // Load property array property.
487 __ bind(&property_array_property);
488 __ movq(rax, FieldOperand(rdx, JSObject::kPropertiesOffset));
489 __ movq(rax, FieldOperand(rax, rdi, times_pointer_size,
490 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000491 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000492 __ ret(0);
493
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494 // Do a quick inline probe of the receiver's dictionary, if it
495 // exists.
496 __ bind(&probe_dictionary);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000497 // rdx: receiver
498 // rax: key
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000499 // rbx: elements
500
501 __ movq(rcx, FieldOperand(rdx, JSObject::kMapOffset));
502 __ movb(rcx, FieldOperand(rcx, Map::kInstanceTypeOffset));
503 GenerateGlobalInstanceTypeCheck(masm, rcx, &slow);
504
505 GenerateDictionaryLoad(masm, &slow, rbx, rax, rcx, rdi, rax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000506 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000507 __ ret(0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000508
ulan@chromium.org750145a2013-03-07 15:14:13 +0000509 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000510 __ IndexFromHash(rbx, rax);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000511 __ jmp(&index_smi);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000512}
513
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000514
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000515void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
516 // ----------- S t a t e -------------
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000517 // -- rax : key
518 // -- rdx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000519 // -- rsp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000520 // -----------------------------------
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000521 Label miss;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000522
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000523 Register receiver = rdx;
524 Register index = rax;
danno@chromium.orgc612e022011-11-10 11:38:15 +0000525 Register scratch = rcx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000526 Register result = rax;
ager@chromium.org357bf652010-04-12 11:30:10 +0000527
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000528 StringCharAtGenerator char_at_generator(receiver,
529 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000530 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000531 result,
532 &miss, // When not a string.
533 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000534 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000535 STRING_INDEX_IS_ARRAY_INDEX);
536 char_at_generator.GenerateFast(masm);
537 __ ret(0);
ager@chromium.org357bf652010-04-12 11:30:10 +0000538
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000540 char_at_generator.GenerateSlow(masm, call_helper);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000541
ager@chromium.org357bf652010-04-12 11:30:10 +0000542 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000543 GenerateMiss(masm, MISS);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000544}
545
546
ager@chromium.org5c838252010-02-19 08:53:10 +0000547void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000548 // ----------- S t a t e -------------
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000549 // -- rax : key
550 // -- rdx : receiver
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000551 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000552 // -----------------------------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000553 Label slow;
554
ager@chromium.org5c838252010-02-19 08:53:10 +0000555 // Check that the receiver isn't a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000556 __ JumpIfSmi(rdx, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000557
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000558 // Check that the key is an array index, that is Uint32.
559 STATIC_ASSERT(kSmiValueSize <= 32);
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000560 __ JumpUnlessNonNegativeSmi(rax, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000561
562 // Get the map of the receiver.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000563 __ movq(rcx, FieldOperand(rdx, HeapObject::kMapOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000564
565 // Check that it has indexed interceptor and access checks
566 // are not enabled for this object.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000567 __ movb(rcx, FieldOperand(rcx, Map::kBitFieldOffset));
568 __ andb(rcx, Immediate(kSlowCaseBitFieldMask));
569 __ cmpb(rcx, Immediate(1 << Map::kHasIndexedInterceptor));
ager@chromium.org5c838252010-02-19 08:53:10 +0000570 __ j(not_zero, &slow);
571
572 // Everything is fine, call runtime.
danno@chromium.org59400602013-08-13 17:09:37 +0000573 __ PopReturnAddressTo(rcx);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000574 __ push(rdx); // receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000575 __ push(rax); // key
danno@chromium.org59400602013-08-13 17:09:37 +0000576 __ PushReturnAddressFrom(rcx);
ager@chromium.org5c838252010-02-19 08:53:10 +0000577
578 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 __ TailCallExternalReference(
580 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
581 masm->isolate()),
582 2,
583 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000584
585 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000586 GenerateMiss(masm, MISS);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000587}
588
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000589
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000590static void KeyedStoreGenerateGenericHelper(
591 MacroAssembler* masm,
592 Label* fast_object,
593 Label* fast_double,
594 Label* slow,
595 KeyedStoreCheckMap check_map,
596 KeyedStoreIncrementLength increment_length) {
597 Label transition_smi_elements;
598 Label finish_object_store, non_double_value, transition_double_elements;
599 Label fast_double_without_map_check;
600 // Fast case: Do the store, could be either Object or double.
601 __ bind(fast_object);
602 // rax: value
603 // rbx: receiver's elements array (a FixedArray)
604 // rcx: index
605 // rdx: receiver (a JSArray)
606 // r9: map of receiver
607 if (check_map == kCheckMap) {
608 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
609 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
610 __ j(not_equal, fast_double);
611 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000612
613 // HOLECHECK: guards "A[i] = V"
614 // We have to go to the runtime if the current value is the hole because
615 // there may be a callback on the element
616 Label holecheck_passed1;
617 __ movq(kScratchRegister, FieldOperand(rbx,
618 rcx,
619 times_pointer_size,
620 FixedArray::kHeaderSize));
621 __ CompareRoot(kScratchRegister, Heap::kTheHoleValueRootIndex);
622 __ j(not_equal, &holecheck_passed1);
623 __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow);
624
625 __ bind(&holecheck_passed1);
626
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000627 // Smi stores don't require further checks.
628 Label non_smi_value;
629 __ JumpIfNotSmi(rax, &non_smi_value);
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 // It's irrelevant whether array is smi-only or not when writing a smi.
636 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
637 rax);
638 __ ret(0);
639
640 __ bind(&non_smi_value);
641 // Writing a non-smi, check whether array allows non-smi elements.
642 // r9: receiver's map
643 __ CheckFastObjectElements(r9, &transition_smi_elements);
644
645 __ bind(&finish_object_store);
646 if (increment_length == kIncrementLength) {
647 // Add 1 to receiver->length.
648 __ leal(rdi, Operand(rcx, 1));
649 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
650 }
651 __ movq(FieldOperand(rbx, rcx, times_pointer_size, FixedArray::kHeaderSize),
652 rax);
653 __ movq(rdx, rax); // Preserve the value which is returned.
654 __ RecordWriteArray(
655 rbx, rdx, rcx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
656 __ ret(0);
657
658 __ bind(fast_double);
659 if (check_map == kCheckMap) {
660 // Check for fast double array case. If this fails, call through to the
661 // runtime.
662 // rdi: elements array's map
663 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
664 __ j(not_equal, slow);
665 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000666
667 // HOLECHECK: guards "A[i] double hole?"
668 // We have to see if the double version of the hole is present. If so
669 // go to the runtime.
670 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
671 __ cmpl(FieldOperand(rbx, rcx, times_8, offset), Immediate(kHoleNanUpper32));
672 __ j(not_equal, &fast_double_without_map_check);
673 __ JumpIfDictionaryInPrototypeChain(rdx, rdi, kScratchRegister, slow);
674
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000675 __ bind(&fast_double_without_map_check);
676 __ StoreNumberToDoubleElements(rax, rbx, rcx, xmm0,
677 &transition_double_elements);
678 if (increment_length == kIncrementLength) {
679 // Add 1 to receiver->length.
680 __ leal(rdi, Operand(rcx, 1));
681 __ Integer32ToSmiField(FieldOperand(rdx, JSArray::kLengthOffset), rdi);
682 }
683 __ ret(0);
684
685 __ bind(&transition_smi_elements);
686 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
687
688 // Transition the array appropriately depending on the value type.
689 __ movq(r9, FieldOperand(rax, HeapObject::kMapOffset));
690 __ CompareRoot(r9, Heap::kHeapNumberMapRootIndex);
691 __ j(not_equal, &non_double_value);
692
693 // Value is a double. Transition FAST_SMI_ELEMENTS ->
694 // FAST_DOUBLE_ELEMENTS and complete the store.
695 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
696 FAST_DOUBLE_ELEMENTS,
697 rbx,
698 rdi,
699 slow);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000700 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
701 FAST_DOUBLE_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000702 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000703 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
704 __ jmp(&fast_double_without_map_check);
705
706 __ bind(&non_double_value);
707 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
708 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
709 FAST_ELEMENTS,
710 rbx,
711 rdi,
712 slow);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000713 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000714 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
715 slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000716 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
717 __ jmp(&finish_object_store);
718
719 __ bind(&transition_double_elements);
720 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
721 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
722 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
723 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
724 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
725 FAST_ELEMENTS,
726 rbx,
727 rdi,
728 slow);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000729 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000730 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000731 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
732 __ jmp(&finish_object_store);
733}
734
735
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000736void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
737 StrictModeFlag strict_mode) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000738 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000739 // -- rax : value
740 // -- rcx : key
741 // -- rdx : receiver
742 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000743 // -----------------------------------
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000744 Label slow, slow_with_tagged_index, fast_object, fast_object_grow;
745 Label fast_double, fast_double_grow;
746 Label array, extra, check_if_double_array;
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000747
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000748 // Check that the object isn't a smi.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000749 __ JumpIfSmi(rdx, &slow_with_tagged_index);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000750 // Get the map from the receiver.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000751 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000752 // Check that the receiver does not require access checks and is not observed.
753 // The generic stub does not perform map checks or handle observed objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000754 __ testb(FieldOperand(r9, Map::kBitFieldOffset),
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000755 Immediate(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000756 __ j(not_zero, &slow_with_tagged_index);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000757 // Check that the key is a smi.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000758 __ JumpIfNotSmi(rcx, &slow_with_tagged_index);
759 __ SmiToInteger32(rcx, rcx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000760
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000761 __ CmpInstanceType(r9, JS_ARRAY_TYPE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000762 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000763 // Check that the object is some kind of JSObject.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000764 __ CmpInstanceType(r9, FIRST_JS_OBJECT_TYPE);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000765 __ j(below, &slow);
766
767 // Object case: Check key against length in the elements array.
768 // rax: value
769 // rdx: JSObject
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000770 // rcx: index
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000771 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000772 // Check array bounds.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000773 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000774 // rax: value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000775 // rbx: FixedArray
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000776 // rcx: index
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000777 __ j(above, &fast_object);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000778
ager@chromium.org3811b432009-10-28 14:53:37 +0000779 // Slow case: call runtime.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000780 __ bind(&slow);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000781 __ Integer32ToSmi(rcx, rcx);
782 __ bind(&slow_with_tagged_index);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000783 GenerateRuntimeSetProperty(masm, strict_mode);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000784 // Never returns to here.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000785
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000786 // Extra capacity case: Check if there is extra capacity to
787 // perform the store and update the length. Used for adding one
788 // element to the array by writing to array[array.length].
789 __ bind(&extra);
790 // rax: value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000791 // rdx: receiver (a JSArray)
792 // rbx: receiver's elements array (a FixedArray)
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000793 // rcx: index
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000794 // flags: smicompare (rdx.length(), rbx)
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000795 __ j(not_equal, &slow); // do not leave holes in the array
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000796 __ SmiCompareInteger32(FieldOperand(rbx, FixedArray::kLengthOffset), rcx);
797 __ j(below_equal, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000798 // Increment index to get new length.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000799 __ movq(rdi, FieldOperand(rbx, HeapObject::kMapOffset));
800 __ CompareRoot(rdi, Heap::kFixedArrayMapRootIndex);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000801 __ j(not_equal, &check_if_double_array);
802 __ jmp(&fast_object_grow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000803
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000804 __ bind(&check_if_double_array);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000805 // rdi: elements array's map
806 __ CompareRoot(rdi, Heap::kFixedDoubleArrayMapRootIndex);
807 __ j(not_equal, &slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000808 __ jmp(&fast_double_grow);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000809
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000810 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000811 // array. Check that the array is in fast mode (and writable); if it
812 // is the length is always a smi.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000813 __ bind(&array);
814 // rax: value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000815 // rdx: receiver (a JSArray)
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000816 // rcx: index
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000817 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000818
819 // Check the key against the length in the array, compute the
820 // address to store into and fall through to fast case.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000821 __ SmiCompareInteger32(FieldOperand(rdx, JSArray::kLengthOffset), rcx);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000822 __ j(below_equal, &extra);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000823
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000824 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
825 &slow, kCheckMap, kDontIncrementLength);
826 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
827 &slow, kDontCheckMap, kIncrementLength);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000828}
829
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000830
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000831// The generated code does not accept smi keys.
832// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000833void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
834 int argc,
835 Code::Kind kind,
836 Code::ExtraICState extra_state) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000837 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000838 // rcx : function name
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000839 // rdx : receiver
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000840 // -----------------------------------
841 Label number, non_number, non_string, boolean, probe, miss;
842
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000843 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000844 Code::Flags flags = Code::ComputeFlags(kind,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000845 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000846 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000847 Code::NORMAL,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000848 argc);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000849 masm->isolate()->stub_cache()->GenerateProbe(
850 masm, flags, rdx, rcx, rbx, rax);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000851
852 // If the stub cache probing failed, the receiver might be a value.
853 // For value objects, we use the map of the prototype objects for
854 // the corresponding JSValue for the cache and that is what we need
855 // to probe.
856 //
857 // Check for number.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000858 __ JumpIfSmi(rdx, &number);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000859 __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx);
860 __ j(not_equal, &non_number);
861 __ bind(&number);
862 StubCompiler::GenerateLoadGlobalFunctionPrototype(
863 masm, Context::NUMBER_FUNCTION_INDEX, rdx);
864 __ jmp(&probe);
865
866 // Check for string.
867 __ bind(&non_number);
868 __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE);
869 __ j(above_equal, &non_string);
870 StubCompiler::GenerateLoadGlobalFunctionPrototype(
871 masm, Context::STRING_FUNCTION_INDEX, rdx);
872 __ jmp(&probe);
873
874 // Check for boolean.
875 __ bind(&non_string);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000876 __ CompareRoot(rdx, Heap::kTrueValueRootIndex);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000877 __ j(equal, &boolean);
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000878 __ CompareRoot(rdx, Heap::kFalseValueRootIndex);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000879 __ j(not_equal, &miss);
880 __ bind(&boolean);
881 StubCompiler::GenerateLoadGlobalFunctionPrototype(
882 masm, Context::BOOLEAN_FUNCTION_INDEX, rdx);
883
884 // Probe the stub cache for the value object.
885 __ bind(&probe);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000886 masm->isolate()->stub_cache()->GenerateProbe(
887 masm, flags, rdx, rcx, rbx, no_reg);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000888
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000889 __ bind(&miss);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000890}
891
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000892
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000893static void GenerateFunctionTailCall(MacroAssembler* masm,
894 int argc,
895 Label* miss) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000896 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000897 // rcx : function name
898 // rdi : function
899 // rsp[0] : return address
900 // rsp[8] : argument argc
901 // rsp[16] : argument argc - 1
ager@chromium.org5c838252010-02-19 08:53:10 +0000902 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000903 // rsp[argc * 8] : argument 1
904 // rsp[(argc + 1) * 8] : argument 0 = receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000905 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000906 __ JumpIfSmi(rdi, miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000907 // Check that the value is a JavaScript function.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000908 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rdx);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000909 __ j(not_equal, miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000910
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000911 // Invoke the function.
912 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000913 __ InvokeFunction(rdi, actual, JUMP_FUNCTION,
914 NullCallWrapper(), CALL_AS_METHOD);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000915}
916
917
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000918// The generated code falls through if the call should be handled by runtime.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000919void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000920 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000921 // rcx : function name
922 // rsp[0] : return address
923 // rsp[8] : argument argc
924 // rsp[16] : argument argc - 1
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000925 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000926 // rsp[argc * 8] : argument 1
927 // rsp[(argc + 1) * 8] : argument 0 = receiver
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000928 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000929 Label miss;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000930
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000931 StackArgumentsAccessor args(rsp, argc);
932 __ movq(rdx, args.GetReceiverOperand());
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000933
ulan@chromium.org750145a2013-03-07 15:14:13 +0000934 GenerateNameDictionaryReceiverCheck(masm, rdx, rax, rbx, &miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000935
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000936 // rax: elements
937 // Search the dictionary placing the result in rdi.
938 GenerateDictionaryLoad(masm, &miss, rax, rcx, rbx, rdi, rdi);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000939
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000940 GenerateFunctionTailCall(masm, argc, &miss);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000941
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000942 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000943}
944
945
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000946void CallICBase::GenerateMiss(MacroAssembler* masm,
947 int argc,
948 IC::UtilityId id,
949 Code::ExtraICState extra_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000950 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000951 // rcx : function name
952 // rsp[0] : return address
953 // rsp[8] : argument argc
954 // rsp[16] : argument argc - 1
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000955 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +0000956 // rsp[argc * 8] : argument 1
957 // rsp[(argc + 1) * 8] : argument 0 = receiver
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000958 // -----------------------------------
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000959
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000960 Counters* counters = masm->isolate()->counters();
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000961 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000962 __ IncrementCounter(counters->call_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000963 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000964 __ IncrementCounter(counters->keyed_call_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000965 }
966
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000967 StackArgumentsAccessor args(rsp, argc);
968 __ movq(rdx, args.GetReceiverOperand());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000969
970 // Enter an internal frame.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000971 {
972 FrameScope scope(masm, StackFrame::INTERNAL);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000973
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000974 // Push the receiver and the name of the function.
975 __ push(rdx);
976 __ push(rcx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000977
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000978 // Call the entry.
979 CEntryStub stub(1);
980 __ Set(rax, 2);
981 __ LoadAddress(rbx, ExternalReference(IC_Utility(id), masm->isolate()));
982 __ CallStub(&stub);
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000983
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000984 // Move result to rdi and exit the internal frame.
985 __ movq(rdi, rax);
986 }
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000987
988 // Check if the receiver is a global object of some sort.
989 // This can happen only for regular CallIC but not KeyedCallIC.
990 if (id == IC::kCallIC_Miss) {
991 Label invoke, global;
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000992 __ movq(rdx, args.GetReceiverOperand());
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000993 __ JumpIfSmi(rdx, &invoke);
994 __ CmpObjectType(rdx, JS_GLOBAL_OBJECT_TYPE, rcx);
995 __ j(equal, &global);
996 __ CmpInstanceType(rcx, JS_BUILTINS_OBJECT_TYPE);
997 __ j(not_equal, &invoke);
998
999 // Patch the receiver on the stack.
1000 __ bind(&global);
1001 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001002 __ movq(args.GetReceiverOperand(), rdx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001003 __ bind(&invoke);
1004 }
1005
1006 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001007 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +00001008 ? CALL_AS_FUNCTION
1009 : CALL_AS_METHOD;
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001010 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001011 __ InvokeFunction(rdi,
1012 actual,
1013 JUMP_FUNCTION,
1014 NullCallWrapper(),
1015 call_kind);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001016}
1017
1018
danno@chromium.org40cb8782011-05-25 07:58:50 +00001019void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1020 int argc,
1021 Code::ExtraICState extra_ic_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001022 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001023 // rcx : function name
1024 // rsp[0] : return address
1025 // rsp[8] : argument argc
1026 // rsp[16] : argument argc - 1
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001027 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001028 // rsp[argc * 8] : argument 1
1029 // rsp[(argc + 1) * 8] : argument 0 = receiver
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001030 // -----------------------------------
1031
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001032 StackArgumentsAccessor args(rsp, argc);
1033 __ movq(rdx, args.GetReceiverOperand());
danno@chromium.org40cb8782011-05-25 07:58:50 +00001034 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
1035 GenerateMiss(masm, argc, extra_ic_state);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001036}
1037
1038
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001039void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001040 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001041 // rcx : function name
1042 // rsp[0] : return address
1043 // rsp[8] : argument argc
1044 // rsp[16] : argument argc - 1
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001045 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001046 // rsp[argc * 8] : argument 1
1047 // rsp[(argc + 1) * 8] : argument 0 = receiver
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001048 // -----------------------------------
1049
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001050 StackArgumentsAccessor args(rsp, argc);
1051 __ movq(rdx, args.GetReceiverOperand());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001052
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001053 Label do_call, slow_call, slow_load;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001054 Label check_number_dictionary, check_name, lookup_monomorphic_cache;
1055 Label index_smi, index_name;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001056
1057 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001058 __ JumpIfNotSmi(rcx, &check_name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001059
1060 __ bind(&index_smi);
1061 // Now the key is known to be a smi. This place is also jumped to from below
1062 // where a numeric string is converted to a smi.
1063
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001064 GenerateKeyedLoadReceiverCheck(
1065 masm, rdx, rax, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001066
1067 GenerateFastArrayLoad(
1068 masm, rdx, rcx, rax, rbx, rdi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001069 Counters* counters = masm->isolate()->counters();
1070 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001071
1072 __ bind(&do_call);
1073 // receiver in rdx is not used after this point.
1074 // rcx: key
1075 // rdi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001076 GenerateFunctionTailCall(masm, argc, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001077
1078 __ bind(&check_number_dictionary);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001079 // rax: elements
1080 // rcx: smi key
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001081 // Check whether the elements is a number dictionary.
1082 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset),
1083 Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001084 __ j(not_equal, &slow_load);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001085 __ SmiToInteger32(rbx, rcx);
1086 // ebx: untagged index
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001087 __ LoadFromNumberDictionary(&slow_load, rax, rcx, rbx, r9, rdi, rdi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001088 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001089 __ jmp(&do_call);
1090
1091 __ bind(&slow_load);
1092 // This branch is taken when calling KeyedCallIC_Miss is neither required
1093 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001094 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001095 {
1096 FrameScope scope(masm, StackFrame::INTERNAL);
1097 __ push(rcx); // save the key
1098 __ push(rdx); // pass the receiver
1099 __ push(rcx); // pass the key
1100 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1101 __ pop(rcx); // restore the key
1102 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001103 __ movq(rdi, rax);
1104 __ jmp(&do_call);
1105
ulan@chromium.org750145a2013-03-07 15:14:13 +00001106 __ bind(&check_name);
1107 GenerateKeyNameCheck(masm, rcx, rax, rbx, &index_name, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001108
ulan@chromium.org750145a2013-03-07 15:14:13 +00001109 // The key is known to be a unique name.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001110 // If the receiver is a regular JS object with slow properties then do
1111 // a quick inline probe of the receiver's dictionary.
1112 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001113 GenerateKeyedLoadReceiverCheck(
1114 masm, rdx, rax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001115
1116 __ movq(rbx, FieldOperand(rdx, JSObject::kPropertiesOffset));
1117 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
1118 Heap::kHashTableMapRootIndex);
1119 __ j(not_equal, &lookup_monomorphic_cache);
1120
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001121 GenerateDictionaryLoad(masm, &slow_load, rbx, rcx, rax, rdi, rdi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001122 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001123 __ jmp(&do_call);
1124
1125 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001126 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001127 GenerateMonomorphicCacheProbe(masm,
1128 argc,
1129 Code::KEYED_CALL_IC,
1130 Code::kNoExtraICState);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001131 // Fall through on miss.
1132
1133 __ bind(&slow_call);
1134 // This branch is taken if:
1135 // - the receiver requires boxing or access check,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001136 // - the key is neither smi nor a unique name,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001137 // - the value loaded is not a function,
1138 // - there is hope that the runtime will create a monomorphic call stub
1139 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001140 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001141 GenerateMiss(masm, argc);
1142
ulan@chromium.org750145a2013-03-07 15:14:13 +00001143 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001144 __ IndexFromHash(rbx, rcx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001145 // Now jump to the place where smi keys are handled.
1146 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001147}
1148
1149
1150void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001151 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001152 // rcx : function name
1153 // rsp[0] : return address
1154 // rsp[8] : argument argc
1155 // rsp[16] : argument argc - 1
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001156 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001157 // rsp[argc * 8] : argument 1
1158 // rsp[(argc + 1) * 8] : argument 0 = receiver
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001159 // -----------------------------------
1160
ulan@chromium.org750145a2013-03-07 15:14:13 +00001161 // Check if the name is really a name.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001162 Label miss;
1163 __ JumpIfSmi(rcx, &miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001164 Condition cond = masm->IsObjectNameType(rcx, rax, rax);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001165 __ j(NegateCondition(cond), &miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001166 CallICBase::GenerateNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001167 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001168 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001169}
1170
1171
whesse@chromium.org7b260152011-06-20 15:33:18 +00001172static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
1173 Register object,
1174 Register key,
1175 Register scratch1,
1176 Register scratch2,
1177 Register scratch3,
1178 Label* unmapped_case,
1179 Label* slow_case) {
1180 Heap* heap = masm->isolate()->heap();
1181
ager@chromium.org04921a82011-06-27 13:21:41 +00001182 // Check that the receiver is a JSObject. Because of the elements
1183 // map check later, we do not need to check for interceptors or
1184 // whether it requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001185 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +00001186 // Check that the object is some kind of JSObject.
1187 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
1188 __ j(below, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001189
1190 // Check that the key is a positive smi.
1191 Condition check = masm->CheckNonNegativeSmi(key);
1192 __ j(NegateCondition(check), slow_case);
1193
1194 // Load the elements into scratch1 and check its map. If not, jump
1195 // to the unmapped lookup with the parameter map in scratch1.
1196 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
1197 __ movq(scratch1, FieldOperand(object, JSObject::kElementsOffset));
1198 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
1199
1200 // Check if element is in the range of mapped arguments.
1201 __ movq(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
1202 __ SmiSubConstant(scratch2, scratch2, Smi::FromInt(2));
1203 __ cmpq(key, scratch2);
1204 __ j(greater_equal, unmapped_case);
1205
1206 // Load element index and check whether it is the hole.
1207 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
1208 __ SmiToInteger64(scratch3, key);
1209 __ movq(scratch2, FieldOperand(scratch1,
1210 scratch3,
1211 times_pointer_size,
1212 kHeaderSize));
1213 __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex);
1214 __ j(equal, unmapped_case);
1215
1216 // Load value from context and return it. We can reuse scratch1 because
1217 // we do not jump to the unmapped lookup (which requires the parameter
1218 // map in scratch1).
1219 __ movq(scratch1, FieldOperand(scratch1, FixedArray::kHeaderSize));
1220 __ SmiToInteger64(scratch3, scratch2);
1221 return FieldOperand(scratch1,
1222 scratch3,
1223 times_pointer_size,
1224 Context::kHeaderSize);
1225}
1226
1227
1228static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
1229 Register key,
1230 Register parameter_map,
1231 Register scratch,
1232 Label* slow_case) {
1233 // Element is in arguments backing store, which is referenced by the
1234 // second element of the parameter_map. The parameter_map register
1235 // must be loaded with the parameter map of the arguments object and is
1236 // overwritten.
1237 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
1238 Register backing_store = parameter_map;
1239 __ movq(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001240 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
1241 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001242 __ movq(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
1243 __ cmpq(key, scratch);
1244 __ j(greater_equal, slow_case);
1245 __ SmiToInteger64(scratch, key);
1246 return FieldOperand(backing_store,
1247 scratch,
1248 times_pointer_size,
1249 FixedArray::kHeaderSize);
1250}
1251
1252
1253void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1254 // ----------- S t a t e -------------
1255 // -- rax : key
1256 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001257 // -- rsp[0] : return address
whesse@chromium.org7b260152011-06-20 15:33:18 +00001258 // -----------------------------------
1259 Label slow, notin;
1260 Operand mapped_location =
1261 GenerateMappedArgumentsLookup(
1262 masm, rdx, rax, rbx, rcx, rdi, &notin, &slow);
1263 __ movq(rax, mapped_location);
1264 __ Ret();
1265 __ bind(&notin);
1266 // The unmapped lookup expects that the parameter map is in rbx.
1267 Operand unmapped_location =
1268 GenerateUnmappedArgumentsLookup(masm, rax, rbx, rcx, &slow);
1269 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1270 __ j(equal, &slow);
1271 __ movq(rax, unmapped_location);
1272 __ Ret();
1273 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001274 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001275}
1276
1277
1278void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
1279 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001280 // -- rax : value
1281 // -- rcx : key
1282 // -- rdx : receiver
1283 // -- rsp[0] : return address
whesse@chromium.org7b260152011-06-20 15:33:18 +00001284 // -----------------------------------
1285 Label slow, notin;
1286 Operand mapped_location = GenerateMappedArgumentsLookup(
1287 masm, rdx, rcx, rbx, rdi, r8, &notin, &slow);
1288 __ movq(mapped_location, rax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +00001289 __ lea(r9, mapped_location);
1290 __ movq(r8, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001291 __ RecordWrite(rbx,
1292 r9,
1293 r8,
1294 kDontSaveFPRegs,
1295 EMIT_REMEMBERED_SET,
1296 INLINE_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001297 __ Ret();
1298 __ bind(&notin);
1299 // The unmapped lookup expects that the parameter map is in rbx.
1300 Operand unmapped_location =
1301 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rdi, &slow);
1302 __ movq(unmapped_location, rax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +00001303 __ lea(r9, unmapped_location);
1304 __ movq(r8, rax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001305 __ RecordWrite(rbx,
1306 r9,
1307 r8,
1308 kDontSaveFPRegs,
1309 EMIT_REMEMBERED_SET,
1310 INLINE_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001311 __ Ret();
1312 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001313 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001314}
1315
1316
1317void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1318 int argc) {
1319 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001320 // rcx : function name
1321 // rsp[0] : return address
1322 // rsp[8] : argument argc
1323 // rsp[16] : argument argc - 1
whesse@chromium.org7b260152011-06-20 15:33:18 +00001324 // ...
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001325 // rsp[argc * 8] : argument 1
1326 // rsp[(argc + 1) * 8] : argument 0 = receiver
whesse@chromium.org7b260152011-06-20 15:33:18 +00001327 // -----------------------------------
1328 Label slow, notin;
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001329 StackArgumentsAccessor args(rsp, argc);
1330 __ movq(rdx, args.GetReceiverOperand());
whesse@chromium.org7b260152011-06-20 15:33:18 +00001331 Operand mapped_location = GenerateMappedArgumentsLookup(
1332 masm, rdx, rcx, rbx, rax, r8, &notin, &slow);
1333 __ movq(rdi, mapped_location);
1334 GenerateFunctionTailCall(masm, argc, &slow);
1335 __ bind(&notin);
1336 // The unmapped lookup expects that the parameter map is in rbx.
1337 Operand unmapped_location =
1338 GenerateUnmappedArgumentsLookup(masm, rcx, rbx, rax, &slow);
1339 __ CompareRoot(unmapped_location, Heap::kTheHoleValueRootIndex);
1340 __ j(equal, &slow);
1341 __ movq(rdi, unmapped_location);
1342 GenerateFunctionTailCall(masm, argc, &slow);
1343 __ bind(&slow);
1344 GenerateMiss(masm, argc);
1345}
1346
1347
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001348void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001349 // ----------- S t a t e -------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001350 // -- rax : receiver
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001351 // -- rcx : name
1352 // -- rsp[0] : return address
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001353 // -----------------------------------
1354
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001355 // Probe the stub cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001356 Code::Flags flags = Code::ComputeFlags(
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001357 Code::HANDLER, MONOMORPHIC, Code::kNoExtraICState,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001358 Code::NORMAL, Code::LOAD_IC);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001359 masm->isolate()->stub_cache()->GenerateProbe(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001360 masm, flags, rax, rcx, rbx, rdx);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001361
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001362 GenerateMiss(masm);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001363}
1364
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001365
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001366void LoadIC::GenerateNormal(MacroAssembler* masm) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001367 // ----------- S t a t e -------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001368 // -- rax : receiver
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001369 // -- rcx : name
1370 // -- rsp[0] : return address
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001371 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001372 Label miss;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001373
ulan@chromium.org750145a2013-03-07 15:14:13 +00001374 GenerateNameDictionaryReceiverCheck(masm, rax, rdx, rbx, &miss);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001375
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001376 // rdx: elements
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001377 // Search the dictionary placing the result in rax.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001378 GenerateDictionaryLoad(masm, &miss, rdx, rcx, rbx, rdi, rax);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001379 __ ret(0);
1380
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001381 // Cache miss: Jump to runtime.
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001382 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001383 GenerateMiss(masm);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001384}
1385
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001386
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001387void LoadIC::GenerateMiss(MacroAssembler* masm) {
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001388 // ----------- S t a t e -------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001389 // -- rax : receiver
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001390 // -- rcx : name
1391 // -- rsp[0] : return address
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001392 // -----------------------------------
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00001393
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001394 Counters* counters = masm->isolate()->counters();
1395 __ IncrementCounter(counters->load_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001396
danno@chromium.org59400602013-08-13 17:09:37 +00001397 __ PopReturnAddressTo(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001398 __ push(rax); // receiver
1399 __ push(rcx); // name
danno@chromium.org59400602013-08-13 17:09:37 +00001400 __ PushReturnAddressFrom(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001401
1402 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001403 ExternalReference ref =
1404 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001405 __ TailCallExternalReference(ref, 2, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001406}
1407
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001408
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001409void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1410 // ----------- S t a t e -------------
1411 // -- rax : receiver
1412 // -- rcx : name
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001413 // -- rsp[0] : return address
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001414 // -----------------------------------
1415
danno@chromium.org59400602013-08-13 17:09:37 +00001416 __ PopReturnAddressTo(rbx);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001417 __ push(rax); // receiver
1418 __ push(rcx); // name
danno@chromium.org59400602013-08-13 17:09:37 +00001419 __ PushReturnAddressFrom(rbx);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001420
1421 // Perform tail call to the entry.
1422 __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
1423}
1424
1425
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001426void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001427 // ----------- S t a t e -------------
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001428 // -- rax : key
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001429 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001430 // -- rsp[0] : return address
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001431 // -----------------------------------
1432
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001433 Counters* counters = masm->isolate()->counters();
1434 __ IncrementCounter(counters->keyed_load_miss(), 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001435
danno@chromium.org59400602013-08-13 17:09:37 +00001436 __ PopReturnAddressTo(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001437 __ push(rdx); // receiver
1438 __ push(rax); // name
danno@chromium.org59400602013-08-13 17:09:37 +00001439 __ PushReturnAddressFrom(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001440
1441 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001442 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001443 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1444 masm->isolate())
1445 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001446 __ TailCallExternalReference(ref, 2, 1);
1447}
1448
1449
1450void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1451 // ----------- S t a t e -------------
1452 // -- rax : key
1453 // -- rdx : receiver
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001454 // -- rsp[0] : return address
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001455 // -----------------------------------
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001456
danno@chromium.org59400602013-08-13 17:09:37 +00001457 __ PopReturnAddressTo(rbx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001458 __ push(rdx); // receiver
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001459 __ push(rax); // name
danno@chromium.org59400602013-08-13 17:09:37 +00001460 __ PushReturnAddressFrom(rbx);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001461
1462 // Perform tail call to the entry.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001463 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001464}
1465
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001466
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001467void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001468 StrictModeFlag strict_mode) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001469 // ----------- S t a t e -------------
1470 // -- rax : value
1471 // -- rcx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001472 // -- rdx : receiver
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001473 // -- rsp[0] : return address
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001474 // -----------------------------------
1475
1476 // Get the receiver from the stack and probe the stub cache.
danno@chromium.orgbee51992013-07-10 14:57:15 +00001477 Code::Flags flags = Code::ComputeFlags(
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001478 Code::HANDLER, MONOMORPHIC, strict_mode,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001479 Code::NORMAL, Code::STORE_IC);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001480 masm->isolate()->stub_cache()->GenerateProbe(
1481 masm, flags, rdx, rcx, rbx, no_reg);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00001482
1483 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001484 GenerateMiss(masm);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001485}
1486
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001487
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001488void StoreIC::GenerateMiss(MacroAssembler* masm) {
1489 // ----------- S t a t e -------------
1490 // -- rax : value
1491 // -- rcx : name
1492 // -- rdx : receiver
1493 // -- rsp[0] : return address
1494 // -----------------------------------
1495
danno@chromium.org59400602013-08-13 17:09:37 +00001496 __ PopReturnAddressTo(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001497 __ push(rdx); // receiver
1498 __ push(rcx); // name
1499 __ push(rax); // value
danno@chromium.org59400602013-08-13 17:09:37 +00001500 __ PushReturnAddressFrom(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001501
1502 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001503 ExternalReference ref =
1504 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001505 __ TailCallExternalReference(ref, 3, 1);
1506}
1507
1508
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001509void StoreIC::GenerateNormal(MacroAssembler* masm) {
1510 // ----------- S t a t e -------------
1511 // -- rax : value
1512 // -- rcx : name
1513 // -- rdx : receiver
1514 // -- rsp[0] : return address
1515 // -----------------------------------
1516
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001517 Label miss;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001518
ulan@chromium.org750145a2013-03-07 15:14:13 +00001519 GenerateNameDictionaryReceiverCheck(masm, rdx, rbx, rdi, &miss);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001520
1521 GenerateDictionaryStore(masm, &miss, rbx, rcx, rax, r8, r9);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001522 Counters* counters = masm->isolate()->counters();
1523 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001524 __ ret(0);
1525
1526 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001527 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001528 GenerateMiss(masm);
1529}
1530
1531
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001532void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1533 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001534 // ----------- S t a t e -------------
1535 // -- rax : value
1536 // -- rcx : name
1537 // -- rdx : receiver
1538 // -- rsp[0] : return address
1539 // -----------------------------------
danno@chromium.org59400602013-08-13 17:09:37 +00001540 __ PopReturnAddressTo(rbx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001541 __ push(rdx);
1542 __ push(rcx);
1543 __ push(rax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001544 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1545 __ Push(Smi::FromInt(strict_mode));
danno@chromium.org59400602013-08-13 17:09:37 +00001546 __ PushReturnAddressFrom(rbx);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001547
1548 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001549 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001550}
1551
1552
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001553void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1554 StrictModeFlag strict_mode) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001555 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001556 // -- rax : value
1557 // -- rcx : key
1558 // -- rdx : receiver
1559 // -- rsp[0] : return address
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001560 // -----------------------------------
1561
danno@chromium.org59400602013-08-13 17:09:37 +00001562 __ PopReturnAddressTo(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001563 __ push(rdx); // receiver
1564 __ push(rcx); // key
1565 __ push(rax); // value
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001566 __ Push(Smi::FromInt(NONE)); // PropertyAttributes
1567 __ Push(Smi::FromInt(strict_mode)); // Strict mode.
danno@chromium.org59400602013-08-13 17:09:37 +00001568 __ PushReturnAddressFrom(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001569
1570 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001571 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001572}
1573
1574
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001575void StoreIC::GenerateSlow(MacroAssembler* masm) {
1576 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001577 // -- rax : value
1578 // -- rcx : key
1579 // -- rdx : receiver
1580 // -- rsp[0] : return address
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001581 // -----------------------------------
1582
danno@chromium.org59400602013-08-13 17:09:37 +00001583 __ PopReturnAddressTo(rbx);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001584 __ push(rdx); // receiver
1585 __ push(rcx); // key
1586 __ push(rax); // value
danno@chromium.org59400602013-08-13 17:09:37 +00001587 __ PushReturnAddressFrom(rbx);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001588
1589 // Do tail-call to runtime routine.
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001590 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001591 __ TailCallExternalReference(ref, 3, 1);
1592}
1593
1594
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001595void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001596 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001597 // -- rax : value
1598 // -- rcx : key
1599 // -- rdx : receiver
1600 // -- rsp[0] : return address
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001601 // -----------------------------------
1602
danno@chromium.org59400602013-08-13 17:09:37 +00001603 __ PopReturnAddressTo(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001604 __ push(rdx); // receiver
1605 __ push(rcx); // key
1606 __ push(rax); // value
danno@chromium.org59400602013-08-13 17:09:37 +00001607 __ PushReturnAddressFrom(rbx);
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001608
1609 // Do tail-call to runtime routine.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001610 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1611 __ TailCallExternalReference(ref, 3, 1);
1612}
1613
1614
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001615void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001616 // ----------- S t a t e -------------
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00001617 // -- rax : value
1618 // -- rcx : key
1619 // -- rdx : receiver
1620 // -- rsp[0] : return address
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001621 // -----------------------------------
1622
danno@chromium.org59400602013-08-13 17:09:37 +00001623 __ PopReturnAddressTo(rbx);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001624 __ push(rdx); // receiver
1625 __ push(rcx); // key
1626 __ push(rax); // value
danno@chromium.org59400602013-08-13 17:09:37 +00001627 __ PushReturnAddressFrom(rbx);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001628
1629 // Do tail-call to runtime routine.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001630 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001631 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1632 masm->isolate())
1633 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001634 __ TailCallExternalReference(ref, 3, 1);
1635}
1636
1637
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001638#undef __
1639
1640
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001641Condition CompareIC::ComputeCondition(Token::Value op) {
1642 switch (op) {
1643 case Token::EQ_STRICT:
1644 case Token::EQ:
1645 return equal;
1646 case Token::LT:
1647 return less;
1648 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001649 return greater;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001650 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001651 return less_equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001652 case Token::GTE:
1653 return greater_equal;
1654 default:
1655 UNREACHABLE();
1656 return no_condition;
1657 }
1658}
1659
1660
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001661bool CompareIC::HasInlinedSmiCode(Address address) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001662 // The address of the instruction following the call.
1663 Address test_instruction_address =
1664 address + Assembler::kCallTargetAddressOffset;
1665
1666 // If the instruction following the call is not a test al, nothing
1667 // was inlined.
1668 return *test_instruction_address == Assembler::kTestAlByte;
1669}
1670
1671
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001672void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001673 // The address of the instruction following the call.
1674 Address test_instruction_address =
1675 address + Assembler::kCallTargetAddressOffset;
1676
1677 // If the instruction following the call is not a test al, nothing
1678 // was inlined.
1679 if (*test_instruction_address != Assembler::kTestAlByte) {
1680 ASSERT(*test_instruction_address == Assembler::kNopByte);
1681 return;
1682 }
1683
1684 Address delta_address = test_instruction_address + 1;
1685 // The delta to the start of the map check instruction and the
1686 // condition code uses at the patched jump.
1687 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1688 if (FLAG_trace_ic) {
1689 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1690 address, test_instruction_address, delta);
1691 }
1692
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001693 // Patch with a short conditional jump. Enabling means switching from a short
1694 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
1695 // reverse operation of that.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001696 Address jmp_address = test_instruction_address - delta;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001697 ASSERT((check == ENABLE_INLINED_SMI_CHECK)
1698 ? (*jmp_address == Assembler::kJncShortOpcode ||
1699 *jmp_address == Assembler::kJcShortOpcode)
1700 : (*jmp_address == Assembler::kJnzShortOpcode ||
1701 *jmp_address == Assembler::kJzShortOpcode));
1702 Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1703 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1704 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001705 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001706}
1707
lrn@chromium.org5d00b602011-01-05 09:51:43 +00001708
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001709} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001710
1711#endif // V8_TARGET_ARCH_X64