blob: dab9dd7a447ae089d87419557feba98cce0c4e43 [file] [log] [blame]
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_IA32
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000032#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "ic-inl.h"
34#include "runtime.h"
35#include "stub-cache.h"
36
kasperl@chromium.org71affb52009-05-26 05:44:31 +000037namespace v8 {
38namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040// ----------------------------------------------------------------------------
41// Static IC stub generators.
42//
43
ager@chromium.org65dad4b2009-04-23 08:48:43 +000044#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045
46
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 __ cmp(type, JS_GLOBAL_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000053 __ j(equal, global_object);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000054 __ cmp(type, JS_BUILTINS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000055 __ j(equal, global_object);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000056 __ cmp(type, JS_GLOBAL_PROXY_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000057 __ j(equal, global_object);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000058}
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 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +000075 __ JumpIfSmi(receiver, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000076
77 // Check that the receiver is a valid JS object.
78 __ mov(r1, FieldOperand(receiver, HeapObject::kMapOffset));
79 __ movzx_b(r0, FieldOperand(r1, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000080 __ cmp(r0, FIRST_SPEC_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000081 __ j(below, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000082
83 // If this assert fails, we have to check upper bound too.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000084 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000085
86 GenerateGlobalInstanceTypeCheck(masm, r0, miss);
87
88 // Check for non-global object that requires access check.
89 __ test_b(FieldOperand(r1, Map::kBitFieldOffset),
90 (1 << Map::kIsAccessCheckNeeded) |
91 (1 << Map::kHasNamedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000092 __ j(not_zero, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000093
94 __ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000095 __ CheckMap(r0, masm->isolate()->factory()->hash_table_map(), miss,
96 DONT_DO_SMI_CHECK);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000097}
98
99
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000100// Helper function used to load a property from a dictionary backing
101// storage. This function may fail to load a property even though it is
102// in the dictionary, so code at miss_label must always call a backup
103// property load that is complete. This function is safe to call if
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000104// name is not internalized, and will jump to the miss_label in that
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000105// case. The generated code assumes that the receiver has slow
106// properties, is not a global object and does not have interceptors.
107static void GenerateDictionaryLoad(MacroAssembler* masm,
108 Label* miss_label,
109 Register elements,
110 Register name,
111 Register r0,
112 Register r1,
113 Register result) {
114 // Register use:
115 //
116 // elements - holds the property dictionary on entry and is unchanged.
117 //
118 // name - holds the name of the property on entry and is unchanged.
119 //
120 // Scratch registers:
121 //
122 // r0 - used for the index into the property dictionary
123 //
124 // r1 - used to hold the capacity of the property dictionary.
125 //
126 // result - holds the result on exit.
127
128 Label done;
129
130 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000131 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
132 miss_label,
133 &done,
134 elements,
135 name,
136 r0,
137 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000138
139 // If probing finds an entry in the dictionary, r0 contains the
140 // index into the dictionary. Check that the value is a normal
141 // property.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000142 __ bind(&done);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000143 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000144 NameDictionary::kHeaderSize +
145 NameDictionary::kElementsStartIndex * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000147 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000148 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000149 __ j(not_zero, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150
151 // Get the value at the masked, scaled index.
152 const int kValueOffset = kElementsStartOffset + kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000153 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154}
155
156
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000157// Helper function used to store a property to a dictionary backing
158// storage. This function may fail to store a property eventhough it
159// is in the dictionary, so code at miss_label must always call a
160// backup property store that is complete. This function is safe to
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000161// call if name is not internalized, and will jump to the miss_label in
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000162// that case. The generated code assumes that the receiver has slow
163// properties, is not a global object and does not have interceptors.
164static void GenerateDictionaryStore(MacroAssembler* masm,
165 Label* miss_label,
166 Register elements,
167 Register name,
168 Register value,
169 Register r0,
170 Register r1) {
171 // Register use:
172 //
173 // elements - holds the property dictionary on entry and is clobbered.
174 //
175 // name - holds the name of the property on entry and is unchanged.
176 //
177 // value - holds the value to store and is unchanged.
178 //
179 // r0 - used for index into the property dictionary and is clobbered.
180 //
181 // r1 - used to hold the capacity of the property dictionary and is clobbered.
182 Label done;
183
184
185 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000186 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
187 miss_label,
188 &done,
189 elements,
190 name,
191 r0,
192 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000193
194 // If probing finds an entry in the dictionary, r0 contains the
195 // index into the dictionary. Check that the value is a normal
196 // property that is not read only.
197 __ bind(&done);
198 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000199 NameDictionary::kHeaderSize +
200 NameDictionary::kElementsStartIndex * kPointerSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000201 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000202 const int kTypeAndReadOnlyMask =
203 (PropertyDetails::TypeField::kMask |
204 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000205 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
206 Immediate(kTypeAndReadOnlyMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000207 __ j(not_zero, miss_label);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000208
209 // Store the value at the masked, scaled index.
210 const int kValueOffset = kElementsStartOffset + kPointerSize;
211 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
212 __ mov(Operand(r0, 0), value);
213
214 // Update write barrier. Make sure not to clobber the value.
215 __ mov(r1, value);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000216 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000217}
218
219
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000220// Checks the receiver for special cases (value type, slow case bits).
221// Falls through for regular JS object.
222static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
223 Register receiver,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000224 Register map,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000225 int interceptor_bit,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000226 Label* slow) {
227 // Register use:
228 // receiver - holds the receiver and is unchanged.
229 // Scratch registers:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000230 // map - used to hold the map of the receiver.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000231
232 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000233 __ JumpIfSmi(receiver, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000234
235 // Get the map of the receiver.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000236 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000237
238 // Check bit field.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000239 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000240 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000241 __ j(not_zero, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000242 // 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 works as intended.
246 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
247
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000248 __ CmpInstanceType(map, JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000249 __ j(below, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000250}
251
252
253// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000254// If not_fast_array is NULL, doesn't perform the elements map check.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000255static void GenerateFastArrayLoad(MacroAssembler* masm,
256 Register receiver,
257 Register key,
258 Register scratch,
259 Register result,
260 Label* not_fast_array,
261 Label* out_of_range) {
262 // Register use:
263 // receiver - holds the receiver and is unchanged.
264 // key - holds the key and is unchanged (must be a smi).
265 // Scratch registers:
266 // scratch - used to hold elements of the receiver and the loaded value.
267 // result - holds the result on exit if the load succeeds and
268 // we fall through.
269
270 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000271 if (not_fast_array != NULL) {
272 // Check that the object is in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000273 __ CheckMap(scratch,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000274 masm->isolate()->factory()->fixed_array_map(),
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000275 not_fast_array,
276 DONT_DO_SMI_CHECK);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000277 } else {
278 __ AssertFastElements(scratch);
279 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000280 // Check that the key (index) is within bounds.
281 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
282 __ j(above_equal, out_of_range);
283 // Fast case: Do the load.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000284 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000285 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000286 __ cmp(scratch, Immediate(masm->isolate()->factory()->the_hole_value()));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000287 // In case the loaded value is the_hole we have to consult GetProperty
288 // to ensure the prototype chain is searched.
289 __ j(equal, out_of_range);
290 if (!result.is(scratch)) {
291 __ mov(result, scratch);
292 }
293}
294
295
ulan@chromium.org750145a2013-03-07 15:14:13 +0000296// Checks whether a key is an array index string or a unique name.
297// Falls through if the key is a unique name.
298static void GenerateKeyNameCheck(MacroAssembler* masm,
299 Register key,
300 Register map,
301 Register hash,
302 Label* index_string,
303 Label* not_unique) {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000304 // Register use:
305 // key - holds the key and is unchanged. Assumed to be non-smi.
306 // Scratch registers:
307 // map - used to hold the map of the key.
308 // hash - used to hold the hash of the key.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000309 Label unique;
310 __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
311 __ j(above, not_unique);
312 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
313 __ j(equal, &unique);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000314
315 // Is the string an array index, with cached numeric value?
ulan@chromium.org750145a2013-03-07 15:14:13 +0000316 __ mov(hash, FieldOperand(key, Name::kHashFieldOffset));
317 __ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000318 __ j(zero, index_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000319
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000320 // Is the string internalized? We already know it's a string so a single
321 // bit test is enough.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000322 STATIC_ASSERT(kNotInternalizedTag != 0);
323 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset),
324 kIsNotInternalizedMask);
325 __ j(not_zero, not_unique);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000326
327 __ bind(&unique);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000328}
329
330
whesse@chromium.org7b260152011-06-20 15:33:18 +0000331static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
332 Register object,
333 Register key,
334 Register scratch1,
335 Register scratch2,
336 Label* unmapped_case,
337 Label* slow_case) {
338 Heap* heap = masm->isolate()->heap();
339 Factory* factory = masm->isolate()->factory();
340
ager@chromium.org04921a82011-06-27 13:21:41 +0000341 // Check that the receiver is a JSObject. Because of the elements
342 // map check later, we do not need to check for interceptors or
343 // whether it requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000344 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +0000345 // Check that the object is some kind of JSObject.
346 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
347 __ j(below, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000348
349 // Check that the key is a positive smi.
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000350 __ test(key, Immediate(0x80000001));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000351 __ j(not_zero, slow_case);
352
353 // Load the elements into scratch1 and check its map.
354 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
355 __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
356 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
357
358 // Check if element is in the range of mapped arguments. If not, jump
359 // to the unmapped lookup with the parameter map in scratch1.
360 __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000361 __ sub(scratch2, Immediate(Smi::FromInt(2)));
362 __ cmp(key, scratch2);
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000363 __ j(above_equal, unmapped_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000364
365 // Load element index and check whether it is the hole.
366 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
367 __ mov(scratch2, FieldOperand(scratch1,
368 key,
369 times_half_pointer_size,
370 kHeaderSize));
371 __ cmp(scratch2, factory->the_hole_value());
372 __ j(equal, unmapped_case);
373
374 // Load value from context and return it. We can reuse scratch1 because
375 // we do not jump to the unmapped lookup (which requires the parameter
376 // map in scratch1).
377 const int kContextOffset = FixedArray::kHeaderSize;
378 __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
379 return FieldOperand(scratch1,
380 scratch2,
381 times_half_pointer_size,
382 Context::kHeaderSize);
383}
384
385
386static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
387 Register key,
388 Register parameter_map,
389 Register scratch,
390 Label* slow_case) {
391 // Element is in arguments backing store, which is referenced by the
392 // second element of the parameter_map.
393 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
394 Register backing_store = parameter_map;
395 __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000396 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
397 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000398 __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000399 __ cmp(key, scratch);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000400 __ j(greater_equal, slow_case);
401 return FieldOperand(backing_store,
402 key,
403 times_half_pointer_size,
404 FixedArray::kHeaderSize);
405}
406
407
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
409 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000410 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +0000411 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 // -----------------------------------
ulan@chromium.org750145a2013-03-07 15:14:13 +0000414 Label slow, check_name, index_smi, index_name, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000415 Label probe_dictionary, check_number_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000417 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000418 __ JumpIfNotSmi(ecx, &check_name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000419 __ bind(&index_smi);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000420 // Now the key is known to be a smi. This place is also jumped to from
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000421 // where a numeric string is converted to a smi.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000422
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000423 GenerateKeyedLoadReceiverCheck(
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000424 masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000425
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000426 // Check the receiver's map to see if it has fast elements.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000427 __ CheckFastElements(eax, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000428
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000429 GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000430 Isolate* isolate = masm->isolate();
431 Counters* counters = isolate->counters();
432 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000433 __ ret(0);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000434
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000435 __ bind(&check_number_dictionary);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000436 __ mov(ebx, ecx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000437 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000438 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000439
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000440 // Check whether the elements is a number dictionary.
441 // edx: receiver
442 // ebx: untagged index
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000443 // ecx: key
444 // eax: elements
445 __ CheckMap(eax,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000446 isolate->factory()->hash_table_map(),
447 &slow,
448 DONT_DO_SMI_CHECK);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000449 Label slow_pop_receiver;
450 // Push receiver on the stack to free up a register for the dictionary
451 // probing.
452 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000453 __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000454 // Pop receiver before returning.
455 __ pop(edx);
456 __ ret(0);
457
458 __ bind(&slow_pop_receiver);
459 // Pop the receiver from the stack and jump to runtime.
460 __ pop(edx);
461
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462 __ bind(&slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000463 // Slow case: jump to runtime.
464 // edx: receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000465 // ecx: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000466 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000467 GenerateRuntimeGetProperty(masm);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000468
ulan@chromium.org750145a2013-03-07 15:14:13 +0000469 __ bind(&check_name);
470 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000471
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000472 GenerateKeyedLoadReceiverCheck(
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000473 masm, edx, eax, Map::kHasNamedInterceptor, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000474
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000475 // If the receiver is a fast-case object, check the keyed lookup
ager@chromium.org5c838252010-02-19 08:53:10 +0000476 // cache. Otherwise probe the dictionary.
477 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000478 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000479 Immediate(isolate->factory()->hash_table_map()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000480 __ j(equal, &probe_dictionary);
481
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000482 // The receiver's map is still in eax, compute the keyed lookup cache hash
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000483 // based on 32 bits of the map pointer and the string hash.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000484 if (FLAG_debug_code) {
485 __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
danno@chromium.org59400602013-08-13 17:09:37 +0000486 __ Check(equal, kMapIsNoLongerInEax);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000487 }
488 __ mov(ebx, eax); // Keep the map around for later.
489 __ shr(eax, KeyedLookupCache::kMapHashShift);
490 __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000491 __ shr(edi, String::kHashShift);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000492 __ xor_(eax, edi);
493 __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000494
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000495 // Load the key (consisting of map and internalized string) from the cache and
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000496 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000497 Label load_in_object_property;
498 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
499 Label hit_on_nth_entry[kEntriesPerBucket];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 ExternalReference cache_keys =
501 ExternalReference::keyed_lookup_cache_keys(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000502
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000503 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
504 Label try_next_entry;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000505 __ mov(edi, eax);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000506 __ shl(edi, kPointerSizeLog2 + 1);
507 if (i != 0) {
508 __ add(edi, Immediate(kPointerSize * i * 2));
509 }
510 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
511 __ j(not_equal, &try_next_entry);
512 __ add(edi, Immediate(kPointerSize));
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000513 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000514 __ j(equal, &hit_on_nth_entry[i]);
515 __ bind(&try_next_entry);
516 }
517
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000518 __ lea(edi, Operand(eax, 1));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000519 __ shl(edi, kPointerSizeLog2 + 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000520 __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000521 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522 __ j(not_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000523 __ add(edi, Immediate(kPointerSize));
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000524 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000525 __ j(not_equal, &slow);
526
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000527 // Get field offset.
ager@chromium.org5c838252010-02-19 08:53:10 +0000528 // edx : receiver
529 // ebx : receiver's map
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000530 // ecx : key
531 // eax : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 ExternalReference cache_field_offsets =
533 ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000534
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000535 // Hit on nth entry.
536 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
537 __ bind(&hit_on_nth_entry[i]);
538 if (i != 0) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000539 __ add(eax, Immediate(i));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000540 }
541 __ mov(edi,
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000542 Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
543 __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
544 __ sub(edi, eax);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000545 __ j(above_equal, &property_array_property);
546 if (i != 0) {
547 __ jmp(&load_in_object_property);
548 }
549 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550
551 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000552 __ bind(&load_in_object_property);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000553 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
554 __ add(eax, edi);
555 __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000556 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000557 __ ret(0);
558
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000559 // Load property array property.
560 __ bind(&property_array_property);
561 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
562 __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
563 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000564 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000565 __ ret(0);
566
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567 // Do a quick inline probe of the receiver's dictionary, if it
568 // exists.
569 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000570
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000571 __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
572 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
573 GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000574
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000575 GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000576 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 __ ret(0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578
ulan@chromium.org750145a2013-03-07 15:14:13 +0000579 __ bind(&index_name);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000580 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000581 // Now jump to the place where smi keys are handled.
582 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583}
584
585
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000586void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
587 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000588 // -- ecx : key (index)
ager@chromium.org5c838252010-02-19 08:53:10 +0000589 // -- edx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000590 // -- esp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000591 // -----------------------------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000592 Label miss;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000593
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000594 Register receiver = edx;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000595 Register index = ecx;
596 Register scratch = ebx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000597 Register result = eax;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000598
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000599 StringCharAtGenerator char_at_generator(receiver,
600 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000601 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000602 result,
603 &miss, // When not a string.
604 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000605 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000606 STRING_INDEX_IS_ARRAY_INDEX);
607 char_at_generator.GenerateFast(masm);
608 __ ret(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000609
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000610 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000611 char_at_generator.GenerateSlow(masm, call_helper);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000612
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000613 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000614 GenerateMiss(masm, MISS);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000615}
616
617
ager@chromium.org5c838252010-02-19 08:53:10 +0000618void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
619 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000620 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +0000621 // -- edx : receiver
622 // -- esp[0] : return address
623 // -----------------------------------
624 Label slow;
625
626 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000627 __ JumpIfSmi(edx, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000628
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000629 // Check that the key is an array index, that is Uint32.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000630 __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000631 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000632
633 // Get the map of the receiver.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000634 __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000635
636 // Check that it has indexed interceptor and access checks
637 // are not enabled for this object.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000638 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
639 __ and_(eax, Immediate(kSlowCaseBitFieldMask));
640 __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000641 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000642
643 // Everything is fine, call runtime.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000644 __ pop(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +0000645 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000646 __ push(ecx); // key
647 __ push(eax); // return address
ager@chromium.org5c838252010-02-19 08:53:10 +0000648
649 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000650 ExternalReference ref =
651 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
652 masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000653 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000654
655 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000656 GenerateMiss(masm, MISS);
ager@chromium.org3811b432009-10-28 14:53:37 +0000657}
658
659
whesse@chromium.org7b260152011-06-20 15:33:18 +0000660void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
661 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000662 // -- ecx : key
whesse@chromium.org7b260152011-06-20 15:33:18 +0000663 // -- edx : receiver
664 // -- esp[0] : return address
665 // -----------------------------------
666 Label slow, notin;
667 Factory* factory = masm->isolate()->factory();
668 Operand mapped_location =
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000669 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000670 __ mov(eax, mapped_location);
671 __ Ret();
672 __ bind(&notin);
673 // The unmapped lookup expects that the parameter map is in ebx.
674 Operand unmapped_location =
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000675 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000676 __ cmp(unmapped_location, factory->the_hole_value());
677 __ j(equal, &slow);
678 __ mov(eax, unmapped_location);
679 __ Ret();
680 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000681 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000682}
683
684
685void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
686 // ----------- S t a t e -------------
687 // -- eax : value
688 // -- ecx : key
689 // -- edx : receiver
690 // -- esp[0] : return address
691 // -----------------------------------
692 Label slow, notin;
693 Operand mapped_location =
694 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, &notin, &slow);
695 __ mov(mapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000696 __ lea(ecx, mapped_location);
697 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000698 __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000699 __ Ret();
700 __ bind(&notin);
701 // The unmapped lookup expects that the parameter map is in ebx.
702 Operand unmapped_location =
703 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
704 __ mov(unmapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000705 __ lea(edi, unmapped_location);
706 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000707 __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000708 __ Ret();
709 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000710 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000711}
712
713
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000714static void KeyedStoreGenerateGenericHelper(
715 MacroAssembler* masm,
716 Label* fast_object,
717 Label* fast_double,
718 Label* slow,
719 KeyedStoreCheckMap check_map,
720 KeyedStoreIncrementLength increment_length) {
721 Label transition_smi_elements;
722 Label finish_object_store, non_double_value, transition_double_elements;
723 Label fast_double_without_map_check;
724 // eax: value
725 // ecx: key (a smi)
726 // edx: receiver
727 // ebx: FixedArray receiver->elements
728 // edi: receiver map
729 // Fast case: Do the store, could either Object or double.
730 __ bind(fast_object);
731 if (check_map == kCheckMap) {
732 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
733 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
734 __ j(not_equal, fast_double);
735 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000736
737 // HOLECHECK: guards "A[i] = V"
738 // We have to go to the runtime if the current value is the hole because
739 // there may be a callback on the element
740 Label holecheck_passed1;
741 __ cmp(CodeGenerator::FixedArrayElementOperand(ebx, ecx),
742 masm->isolate()->factory()->the_hole_value());
743 __ j(not_equal, &holecheck_passed1);
744 __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow);
745 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
746
747 __ bind(&holecheck_passed1);
748
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000749 // Smi stores don't require further checks.
750 Label non_smi_value;
751 __ JumpIfNotSmi(eax, &non_smi_value);
752 if (increment_length == kIncrementLength) {
753 // Add 1 to receiver->length.
754 __ add(FieldOperand(edx, JSArray::kLengthOffset),
755 Immediate(Smi::FromInt(1)));
756 }
757 // It's irrelevant whether array is smi-only or not when writing a smi.
758 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
759 __ ret(0);
760
761 __ bind(&non_smi_value);
762 // Escape to elements kind transition case.
763 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
764 __ CheckFastObjectElements(edi, &transition_smi_elements);
765
766 // Fast elements array, store the value to the elements backing store.
767 __ bind(&finish_object_store);
768 if (increment_length == kIncrementLength) {
769 // Add 1 to receiver->length.
770 __ add(FieldOperand(edx, JSArray::kLengthOffset),
771 Immediate(Smi::FromInt(1)));
772 }
773 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
774 // Update write barrier for the elements array address.
775 __ mov(edx, eax); // Preserve the value which is returned.
776 __ RecordWriteArray(
777 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
778 __ ret(0);
779
780 __ bind(fast_double);
781 if (check_map == kCheckMap) {
782 // Check for fast double array case. If this fails, call through to the
783 // runtime.
784 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
785 __ j(not_equal, slow);
786 // If the value is a number, store it as a double in the FastDoubleElements
787 // array.
788 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +0000789
790 // HOLECHECK: guards "A[i] double hole?"
791 // We have to see if the double version of the hole is present. If so
792 // go to the runtime.
793 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
794 __ cmp(FieldOperand(ebx, ecx, times_4, offset), Immediate(kHoleNanUpper32));
795 __ j(not_equal, &fast_double_without_map_check);
796 __ JumpIfDictionaryInPrototypeChain(edx, ebx, edi, slow);
797 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
798
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000799 __ bind(&fast_double_without_map_check);
800 __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
801 &transition_double_elements, false);
802 if (increment_length == kIncrementLength) {
803 // Add 1 to receiver->length.
804 __ add(FieldOperand(edx, JSArray::kLengthOffset),
805 Immediate(Smi::FromInt(1)));
806 }
807 __ ret(0);
808
809 __ bind(&transition_smi_elements);
810 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
811
812 // Transition the array appropriately depending on the value type.
813 __ CheckMap(eax,
814 masm->isolate()->factory()->heap_number_map(),
815 &non_double_value,
816 DONT_DO_SMI_CHECK);
817
818 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
819 // and complete the store.
820 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
821 FAST_DOUBLE_ELEMENTS,
822 ebx,
823 edi,
824 slow);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000825 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
826 FAST_DOUBLE_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000827 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000828 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
829 __ jmp(&fast_double_without_map_check);
830
831 __ bind(&non_double_value);
832 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
833 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
834 FAST_ELEMENTS,
835 ebx,
836 edi,
837 slow);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000838 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000839 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
840 slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000841 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
842 __ jmp(&finish_object_store);
843
844 __ bind(&transition_double_elements);
845 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
846 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
847 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
848 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
849 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
850 FAST_ELEMENTS,
851 ebx,
852 edi,
853 slow);
danno@chromium.orgbee51992013-07-10 14:57:15 +0000854 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000855 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000856 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
857 __ jmp(&finish_object_store);
858}
859
860
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000861void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
862 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 // ----------- S t a t e -------------
864 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000865 // -- ecx : key
866 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868 // -----------------------------------
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000869 Label slow, fast_object, fast_object_grow;
870 Label fast_double, fast_double_grow;
871 Label array, extra, check_if_double_array;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000874 __ JumpIfSmi(edx, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000875 // Get the map from the receiver.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000876 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000877 // Check that the receiver does not require access checks and is not observed.
878 // The generic stub does not perform map checks or handle observed objects.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000879 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000880 1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000881 __ j(not_zero, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000882 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000883 __ JumpIfNotSmi(ecx, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000884 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000886 // Check that the object is some kind of JSObject.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000887 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000888 __ j(below, &slow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 // Object case: Check key against length in the elements array.
891 // eax: value
892 // edx: JSObject
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000893 // ecx: key (a smi)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000894 // edi: receiver map
895 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
896 // Check array bounds. Both the key and the length of FixedArray are smis.
897 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000898 __ j(below, &fast_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899
ager@chromium.org3811b432009-10-28 14:53:37 +0000900 // Slow case: call runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901 __ bind(&slow);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000902 GenerateRuntimeSetProperty(masm, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 // Extra capacity case: Check if there is extra capacity to
905 // perform the store and update the length. Used for adding one
906 // element to the array by writing to array[array.length].
907 __ bind(&extra);
908 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000909 // edx: receiver, a JSArray
910 // ecx: key, a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000911 // ebx: receiver->elements, a FixedArray
912 // edi: receiver map
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000913 // flags: compare (ecx, edx.length())
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000914 // do not leave holes in the array:
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000915 __ j(not_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000916 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000917 __ j(above_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000918 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
919 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
920 __ j(not_equal, &check_if_double_array);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000921 __ jmp(&fast_object_grow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000922
923 __ bind(&check_if_double_array);
924 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
925 __ j(not_equal, &slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000926 __ jmp(&fast_double_grow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000929 // array. Check that the array is in fast mode (and writable); if it
930 // is the length is always a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 __ bind(&array);
932 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000933 // edx: receiver, a JSArray
934 // ecx: key, a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000935 // edi: receiver map
936 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000938 // Check the key against the length in the array and fall through to the
939 // common store code.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000940 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000941 __ j(above_equal, &extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000943 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
944 &slow, kCheckMap, kDontIncrementLength);
945 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
946 &slow, kDontCheckMap, kIncrementLength);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947}
948
949
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000950// The generated code does not accept smi keys.
951// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000952void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
953 int argc,
954 Code::Kind kind,
955 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000957 // -- ecx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000958 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000959 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000960 Label number, non_number, non_string, boolean, probe, miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961
962 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000963 Code::Flags flags = Code::ComputeFlags(kind,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000964 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000965 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000966 Code::NORMAL,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000967 argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000968 Isolate* isolate = masm->isolate();
969 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970
971 // If the stub cache probing failed, the receiver might be a value.
972 // For value objects, we use the map of the prototype objects for
973 // the corresponding JSValue for the cache and that is what we need
974 // to probe.
975 //
976 // Check for number.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000977 __ JumpIfSmi(edx, &number);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000978 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000979 __ j(not_equal, &non_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980 __ bind(&number);
981 StubCompiler::GenerateLoadGlobalFunctionPrototype(
982 masm, Context::NUMBER_FUNCTION_INDEX, edx);
983 __ jmp(&probe);
984
985 // Check for string.
986 __ bind(&non_number);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000987 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000988 __ j(above_equal, &non_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989 StubCompiler::GenerateLoadGlobalFunctionPrototype(
990 masm, Context::STRING_FUNCTION_INDEX, edx);
991 __ jmp(&probe);
992
993 // Check for boolean.
994 __ bind(&non_string);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000995 __ cmp(edx, isolate->factory()->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000996 __ j(equal, &boolean);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000997 __ cmp(edx, isolate->factory()->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000998 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999 __ bind(&boolean);
1000 StubCompiler::GenerateLoadGlobalFunctionPrototype(
1001 masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
1002
1003 // Probe the stub cache for the value object.
1004 __ bind(&probe);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001005 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001006 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001010static void GenerateFunctionTailCall(MacroAssembler* masm,
1011 int argc,
1012 Label* miss) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001013 // ----------- S t a t e -------------
1014 // -- ecx : name
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001015 // -- edi : function
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001016 // -- esp[0] : return address
1017 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1018 // -- ...
1019 // -- esp[(argc + 1) * 4] : receiver
1020 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001021
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001022 // Check that the result is not a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001023 __ JumpIfSmi(edi, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001024
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001025 // Check that the value is a JavaScript function, fetching its map into eax.
1026 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001027 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001028
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001029 // Invoke the function.
1030 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001031 __ InvokeFunction(edi, actual, JUMP_FUNCTION,
1032 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001033}
1034
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001035
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001036// The generated code falls through if the call should be handled by runtime.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001037void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001039 // -- ecx : name
1040 // -- esp[0] : return address
1041 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1042 // -- ...
1043 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001045 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046
1047 // Get the receiver of the function from the stack; 1 ~ return address.
1048 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049
ulan@chromium.org750145a2013-03-07 15:14:13 +00001050 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001052 // eax: elements
1053 // Search the dictionary placing the result in edi.
1054 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
1055 GenerateFunctionTailCall(masm, argc, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001056
1057 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058}
1059
1060
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001061void CallICBase::GenerateMiss(MacroAssembler* masm,
1062 int argc,
1063 IC::UtilityId id,
1064 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001066 // -- ecx : name
1067 // -- esp[0] : return address
1068 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1069 // -- ...
1070 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071 // -----------------------------------
1072
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001073 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001074 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001075 __ IncrementCounter(counters->call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001076 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001077 __ IncrementCounter(counters->keyed_call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001078 }
1079
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 // Get the receiver of the function from the stack; 1 ~ return address.
1081 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001083 {
1084 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001086 // Push the receiver and the name of the function.
1087 __ push(edx);
1088 __ push(ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001090 // Call the entry.
1091 CEntryStub stub(1);
1092 __ mov(eax, Immediate(2));
1093 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
1094 __ CallStub(&stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001096 // Move result to edi and exit the internal frame.
1097 __ mov(edi, eax);
1098 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001100 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001101 // This can happen only for regular CallIC but not KeyedCallIC.
1102 if (id == IC::kCallIC_Miss) {
1103 Label invoke, global;
1104 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
whesse@chromium.org7b260152011-06-20 15:33:18 +00001105 __ JumpIfSmi(edx, &invoke, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001106 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1107 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1108 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001109 __ j(equal, &global, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001110 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001111 __ j(not_equal, &invoke, Label::kNear);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001112
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001113 // Patch the receiver on the stack.
1114 __ bind(&global);
1115 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1116 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1117 __ bind(&invoke);
1118 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001119
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001120 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001121 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +00001122 ? CALL_AS_FUNCTION
1123 : CALL_AS_METHOD;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001124 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001125 __ InvokeFunction(edi,
1126 actual,
1127 JUMP_FUNCTION,
1128 NullCallWrapper(),
1129 call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130}
1131
1132
danno@chromium.org40cb8782011-05-25 07:58:50 +00001133void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1134 int argc,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001135 Code::ExtraICState extra_state) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001136 // ----------- S t a t e -------------
1137 // -- ecx : name
1138 // -- esp[0] : return address
1139 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1140 // -- ...
1141 // -- esp[(argc + 1) * 4] : receiver
1142 // -----------------------------------
1143
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001144 // Get the receiver of the function from the stack; 1 ~ return address.
1145 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001146 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
1147 extra_state);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001148
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001149 GenerateMiss(masm, argc, extra_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001150}
1151
1152
1153void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1154 // ----------- S t a t e -------------
1155 // -- ecx : name
1156 // -- esp[0] : return address
1157 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1158 // -- ...
1159 // -- esp[(argc + 1) * 4] : receiver
1160 // -----------------------------------
1161
1162 // Get the receiver of the function from the stack; 1 ~ return address.
1163 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1164
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001165 Label do_call, slow_call, slow_load, slow_reload_receiver;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001166 Label check_number_dictionary, check_name, lookup_monomorphic_cache;
1167 Label index_smi, index_name;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001168
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001169 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001170 __ JumpIfNotSmi(ecx, &check_name);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001171
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001172 __ bind(&index_smi);
1173 // Now the key is known to be a smi. This place is also jumped to from
1174 // where a numeric string is converted to a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001175
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001176 GenerateKeyedLoadReceiverCheck(
1177 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001178
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001179 GenerateFastArrayLoad(
1180 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001181 Isolate* isolate = masm->isolate();
1182 Counters* counters = isolate->counters();
1183 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001184
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001185 __ bind(&do_call);
1186 // receiver in edx is not used after this point.
1187 // ecx: key
1188 // edi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001189 GenerateFunctionTailCall(masm, argc, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001190
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001191 __ bind(&check_number_dictionary);
1192 // eax: elements
1193 // ecx: smi key
1194 // Check whether the elements is a number dictionary.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001195 __ CheckMap(eax,
1196 isolate->factory()->hash_table_map(),
1197 &slow_load,
1198 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001199 __ mov(ebx, ecx);
1200 __ SmiUntag(ebx);
1201 // ebx: untagged index
1202 // Receiver in edx will be clobbered, need to reload it on miss.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001203 __ LoadFromNumberDictionary(
1204 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001205 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001206 __ jmp(&do_call);
1207
1208 __ bind(&slow_reload_receiver);
1209 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1210
1211 __ bind(&slow_load);
1212 // This branch is taken when calling KeyedCallIC_Miss is neither required
1213 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001214 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001215
1216 {
1217 FrameScope scope(masm, StackFrame::INTERNAL);
1218 __ push(ecx); // save the key
1219 __ push(edx); // pass the receiver
1220 __ push(ecx); // pass the key
1221 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1222 __ pop(ecx); // restore the key
1223 // Leave the internal frame.
1224 }
1225
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001226 __ mov(edi, eax);
1227 __ jmp(&do_call);
1228
ulan@chromium.org750145a2013-03-07 15:14:13 +00001229 __ bind(&check_name);
1230 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001231
ulan@chromium.org750145a2013-03-07 15:14:13 +00001232 // The key is known to be a unique name.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001233 // If the receiver is a regular JS object with slow properties then do
1234 // a quick inline probe of the receiver's dictionary.
1235 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001236 GenerateKeyedLoadReceiverCheck(
1237 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001238
1239 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001240 __ CheckMap(ebx,
1241 isolate->factory()->hash_table_map(),
1242 &lookup_monomorphic_cache,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001243 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001244
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001245 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001246 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001247 __ jmp(&do_call);
1248
1249 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001250 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001251 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
1252 Code::kNoExtraICState);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001253 // Fall through on miss.
1254
1255 __ bind(&slow_call);
1256 // This branch is taken if:
1257 // - the receiver requires boxing or access check,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001258 // - the key is neither smi nor a unique name,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001259 // - the value loaded is not a function,
1260 // - there is hope that the runtime will create a monomorphic call stub
1261 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001262 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001263 GenerateMiss(masm, argc);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001264
ulan@chromium.org750145a2013-03-07 15:14:13 +00001265 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001266 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001267 // Now jump to the place where smi keys are handled.
1268 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001269}
1270
1271
whesse@chromium.org7b260152011-06-20 15:33:18 +00001272void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1273 int argc) {
1274 // ----------- S t a t e -------------
1275 // -- ecx : name
1276 // -- esp[0] : return address
1277 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1278 // -- ...
1279 // -- esp[(argc + 1) * 4] : receiver
1280 // -----------------------------------
1281 Label slow, notin;
1282 Factory* factory = masm->isolate()->factory();
1283 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1284 Operand mapped_location =
1285 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
1286 __ mov(edi, mapped_location);
1287 GenerateFunctionTailCall(masm, argc, &slow);
1288 __ bind(&notin);
1289 // The unmapped lookup expects that the parameter map is in ebx.
1290 Operand unmapped_location =
1291 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
1292 __ cmp(unmapped_location, factory->the_hole_value());
1293 __ j(equal, &slow);
1294 __ mov(edi, unmapped_location);
1295 GenerateFunctionTailCall(masm, argc, &slow);
1296 __ bind(&slow);
1297 GenerateMiss(masm, argc);
1298}
1299
1300
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001301void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001302 // ----------- S t a t e -------------
1303 // -- ecx : name
1304 // -- esp[0] : return address
1305 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1306 // -- ...
1307 // -- esp[(argc + 1) * 4] : receiver
1308 // -----------------------------------
1309
ulan@chromium.org750145a2013-03-07 15:14:13 +00001310 // Check if the name is really a name.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001311 Label miss;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001312 __ JumpIfSmi(ecx, &miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001313 Condition cond = masm->IsObjectNameType(ecx, eax, eax);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001314 __ j(NegateCondition(cond), &miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001315 CallICBase::GenerateNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001316 __ bind(&miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001317 GenerateMiss(masm, argc);
1318}
1319
1320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1322 // ----------- S t a t e -------------
1323 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001324 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326 // -----------------------------------
1327
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328 // Probe the stub cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001329 Code::Flags flags = Code::ComputeFlags(
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001330 Code::HANDLER, MONOMORPHIC, Code::kNoExtraICState,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001331 Code::NORMAL, Code::LOAD_IC);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001332 masm->isolate()->stub_cache()->GenerateProbe(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001333 masm, flags, edx, ecx, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334
1335 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +00001336 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337}
1338
1339
1340void LoadIC::GenerateNormal(MacroAssembler* masm) {
1341 // ----------- S t a t e -------------
1342 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001343 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001346 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347
ulan@chromium.org750145a2013-03-07 15:14:13 +00001348 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001350 // eax: elements
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 // Search the dictionary placing the result in eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001352 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 __ ret(0);
1354
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001355 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001357 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358}
1359
1360
1361void LoadIC::GenerateMiss(MacroAssembler* masm) {
1362 // ----------- S t a t e -------------
1363 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001364 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 // -----------------------------------
1367
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001368 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 __ pop(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001371 __ push(edx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001372 __ push(ecx); // name
1373 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374
mads.s.ager31e71382008-08-13 09:32:07 +00001375 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001376 ExternalReference ref =
1377 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001378 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379}
1380
1381
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00001382void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1383 // ----------- S t a t e -------------
1384 // -- ecx : key
1385 // -- edx : receiver
1386 // -- esp[0] : return address
1387 // -----------------------------------
1388
1389 __ pop(ebx);
1390 __ push(edx); // receiver
1391 __ push(ecx); // name
1392 __ push(ebx); // return address
1393
1394 // Perform tail call to the entry.
1395 __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
1396}
1397
1398
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001399void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001401 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00001402 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 // -----------------------------------
1405
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001406 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001407
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 __ pop(ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001409 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001410 __ push(ecx); // name
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001411 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412
mads.s.ager31e71382008-08-13 09:32:07 +00001413 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001414 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001415 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1416 masm->isolate())
1417 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001418 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001419}
1420
1421
1422void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1423 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001424 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00001425 // -- edx : receiver
1426 // -- esp[0] : return address
1427 // -----------------------------------
1428
1429 __ pop(ebx);
1430 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001431 __ push(ecx); // name
ager@chromium.org5c838252010-02-19 08:53:10 +00001432 __ push(ebx); // return address
1433
1434 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001435 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001436}
1437
1438
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001439void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001440 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441 // ----------- S t a t e -------------
1442 // -- eax : value
1443 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001444 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 // -----------------------------------
1447
danno@chromium.orgbee51992013-07-10 14:57:15 +00001448 Code::Flags flags = Code::ComputeFlags(
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001449 Code::HANDLER, MONOMORPHIC, strict_mode,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001450 Code::NORMAL, Code::STORE_IC);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001451 masm->isolate()->stub_cache()->GenerateProbe(
1452 masm, flags, edx, ecx, ebx, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453
1454 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001455 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456}
1457
1458
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001459void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460 // ----------- S t a t e -------------
1461 // -- eax : value
1462 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001463 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 // -----------------------------------
1466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467 __ pop(ebx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001468 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 __ push(ecx);
1470 __ push(eax);
1471 __ push(ebx);
1472
mads.s.ager31e71382008-08-13 09:32:07 +00001473 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001474 ExternalReference ref =
1475 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001476 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477}
1478
1479
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001480void StoreIC::GenerateNormal(MacroAssembler* masm) {
1481 // ----------- S t a t e -------------
1482 // -- eax : value
1483 // -- ecx : name
1484 // -- edx : receiver
1485 // -- esp[0] : return address
1486 // -----------------------------------
1487
1488 Label miss, restore_miss;
1489
ulan@chromium.org750145a2013-03-07 15:14:13 +00001490 GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001491
1492 // A lot of registers are needed for storing to slow case
1493 // objects. Push and restore receiver but rely on
1494 // GenerateDictionaryStore preserving the value and name.
1495 __ push(edx);
1496 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1497 __ Drop(1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001498 Counters* counters = masm->isolate()->counters();
1499 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001500 __ ret(0);
1501
1502 __ bind(&restore_miss);
1503 __ pop(edx);
1504
1505 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001506 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001507 GenerateMiss(masm);
1508}
1509
1510
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001511void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1512 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001513 // ----------- S t a t e -------------
1514 // -- eax : value
1515 // -- ecx : name
1516 // -- edx : receiver
1517 // -- esp[0] : return address
1518 // -----------------------------------
1519 __ pop(ebx);
1520 __ push(edx);
1521 __ push(ecx);
1522 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001523 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1524 __ push(Immediate(Smi::FromInt(strict_mode)));
1525 __ push(ebx); // return address
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001526
1527 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001528 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001529}
1530
1531
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001532void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1533 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // ----------- S t a t e -------------
1535 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001536 // -- ecx : key
1537 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539 // -----------------------------------
1540
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001541 __ pop(ebx);
1542 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001544 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001545 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1546 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode.
1547 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548
1549 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001550 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551}
1552
1553
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001554void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001555 // ----------- S t a t e -------------
1556 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001557 // -- ecx : key
1558 // -- edx : receiver
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001559 // -- esp[0] : return address
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001560 // -----------------------------------
1561
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001562 __ pop(ebx);
1563 __ push(edx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001564 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001565 __ push(eax);
1566 __ push(ebx);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001567
1568 // Do tail-call to runtime routine.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001569 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001570 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1571 masm->isolate())
1572 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1573 __ TailCallExternalReference(ref, 3, 1);
1574}
1575
1576
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001577void StoreIC::GenerateSlow(MacroAssembler* masm) {
1578 // ----------- S t a t e -------------
1579 // -- eax : value
1580 // -- ecx : key
1581 // -- edx : receiver
1582 // -- esp[0] : return address
1583 // -----------------------------------
1584
1585 __ pop(ebx);
1586 __ push(edx);
1587 __ push(ecx);
1588 __ push(eax);
1589 __ push(ebx); // return address
1590
1591 // Do tail-call to runtime routine.
1592 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
1593 __ TailCallExternalReference(ref, 3, 1);
1594}
1595
1596
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001597void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1598 // ----------- S t a t e -------------
1599 // -- eax : value
1600 // -- ecx : key
1601 // -- edx : receiver
1602 // -- esp[0] : return address
1603 // -----------------------------------
1604
1605 __ pop(ebx);
1606 __ push(edx);
1607 __ push(ecx);
1608 __ push(eax);
1609 __ push(ebx); // return address
1610
1611 // Do tail-call to runtime routine.
1612 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001613 __ TailCallExternalReference(ref, 3, 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001614}
1615
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617#undef __
1618
1619
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001620Condition CompareIC::ComputeCondition(Token::Value op) {
1621 switch (op) {
1622 case Token::EQ_STRICT:
1623 case Token::EQ:
1624 return equal;
1625 case Token::LT:
1626 return less;
1627 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001628 return greater;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001629 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001630 return less_equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001631 case Token::GTE:
1632 return greater_equal;
1633 default:
1634 UNREACHABLE();
1635 return no_condition;
1636 }
1637}
1638
1639
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001640bool CompareIC::HasInlinedSmiCode(Address address) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001641 // The address of the instruction following the call.
1642 Address test_instruction_address =
1643 address + Assembler::kCallTargetAddressOffset;
1644
1645 // If the instruction following the call is not a test al, nothing
1646 // was inlined.
1647 return *test_instruction_address == Assembler::kTestAlByte;
1648}
1649
1650
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001651void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001652 // The address of the instruction following the call.
1653 Address test_instruction_address =
1654 address + Assembler::kCallTargetAddressOffset;
1655
1656 // If the instruction following the call is not a test al, nothing
1657 // was inlined.
1658 if (*test_instruction_address != Assembler::kTestAlByte) {
1659 ASSERT(*test_instruction_address == Assembler::kNopByte);
1660 return;
1661 }
1662
1663 Address delta_address = test_instruction_address + 1;
1664 // The delta to the start of the map check instruction and the
1665 // condition code uses at the patched jump.
1666 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1667 if (FLAG_trace_ic) {
1668 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1669 address, test_instruction_address, delta);
1670 }
1671
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001672 // Patch with a short conditional jump. Enabling means switching from a short
1673 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
1674 // reverse operation of that.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001675 Address jmp_address = test_instruction_address - delta;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001676 ASSERT((check == ENABLE_INLINED_SMI_CHECK)
1677 ? (*jmp_address == Assembler::kJncShortOpcode ||
1678 *jmp_address == Assembler::kJcShortOpcode)
1679 : (*jmp_address == Assembler::kJnzShortOpcode ||
1680 *jmp_address == Assembler::kJzShortOpcode));
1681 Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1682 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1683 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001684 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001685}
1686
1687
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001688} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001689
1690#endif // V8_TARGET_ARCH_IA32