blob: e05031b8e7b2c52f199e81ad200606ee656f0c95 [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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
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));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +000095 __ CheckMap(r0, FACTORY->hash_table_map(), miss, DONT_DO_SMI_CHECK);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000096}
97
98
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000099// Helper function used to load a property from a dictionary backing
100// storage. This function may fail to load a property even though it is
101// in the dictionary, so code at miss_label must always call a backup
102// property load that is complete. This function is safe to call if
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000103// name is not internalized, and will jump to the miss_label in that
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000104// case. The generated code assumes that the receiver has slow
105// properties, is not a global object and does not have interceptors.
106static void GenerateDictionaryLoad(MacroAssembler* masm,
107 Label* miss_label,
108 Register elements,
109 Register name,
110 Register r0,
111 Register r1,
112 Register result) {
113 // Register use:
114 //
115 // elements - holds the property dictionary on entry and is unchanged.
116 //
117 // name - holds the name of the property on entry and is unchanged.
118 //
119 // Scratch registers:
120 //
121 // r0 - used for the index into the property dictionary
122 //
123 // r1 - used to hold the capacity of the property dictionary.
124 //
125 // result - holds the result on exit.
126
127 Label done;
128
129 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000130 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
131 miss_label,
132 &done,
133 elements,
134 name,
135 r0,
136 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000137
138 // If probing finds an entry in the dictionary, r0 contains the
139 // index into the dictionary. Check that the value is a normal
140 // property.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 __ bind(&done);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000142 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000143 NameDictionary::kHeaderSize +
144 NameDictionary::kElementsStartIndex * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000146 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000147 Immediate(PropertyDetails::TypeField::kMask << kSmiTagSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000148 __ j(not_zero, miss_label);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149
150 // Get the value at the masked, scaled index.
151 const int kValueOffset = kElementsStartOffset + kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000152 __ mov(result, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153}
154
155
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000156// Helper function used to store a property to a dictionary backing
157// storage. This function may fail to store a property eventhough it
158// is in the dictionary, so code at miss_label must always call a
159// backup property store that is complete. This function is safe to
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000160// call if name is not internalized, and will jump to the miss_label in
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000161// that case. The generated code assumes that the receiver has slow
162// properties, is not a global object and does not have interceptors.
163static void GenerateDictionaryStore(MacroAssembler* masm,
164 Label* miss_label,
165 Register elements,
166 Register name,
167 Register value,
168 Register r0,
169 Register r1) {
170 // Register use:
171 //
172 // elements - holds the property dictionary on entry and is clobbered.
173 //
174 // name - holds the name of the property on entry and is unchanged.
175 //
176 // value - holds the value to store and is unchanged.
177 //
178 // r0 - used for index into the property dictionary and is clobbered.
179 //
180 // r1 - used to hold the capacity of the property dictionary and is clobbered.
181 Label done;
182
183
184 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000185 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
186 miss_label,
187 &done,
188 elements,
189 name,
190 r0,
191 r1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000192
193 // If probing finds an entry in the dictionary, r0 contains the
194 // index into the dictionary. Check that the value is a normal
195 // property that is not read only.
196 __ bind(&done);
197 const int kElementsStartOffset =
ulan@chromium.org750145a2013-03-07 15:14:13 +0000198 NameDictionary::kHeaderSize +
199 NameDictionary::kElementsStartIndex * kPointerSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000200 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000201 const int kTypeAndReadOnlyMask =
202 (PropertyDetails::TypeField::kMask |
203 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000204 __ test(Operand(elements, r0, times_4, kDetailsOffset - kHeapObjectTag),
205 Immediate(kTypeAndReadOnlyMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000206 __ j(not_zero, miss_label);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000207
208 // Store the value at the masked, scaled index.
209 const int kValueOffset = kElementsStartOffset + kPointerSize;
210 __ lea(r0, Operand(elements, r0, times_4, kValueOffset - kHeapObjectTag));
211 __ mov(Operand(r0, 0), value);
212
213 // Update write barrier. Make sure not to clobber the value.
214 __ mov(r1, value);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000216}
217
218
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000219// Checks the receiver for special cases (value type, slow case bits).
220// Falls through for regular JS object.
221static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
222 Register receiver,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000223 Register map,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000224 int interceptor_bit,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000225 Label* slow) {
226 // Register use:
227 // receiver - holds the receiver and is unchanged.
228 // Scratch registers:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000229 // map - used to hold the map of the receiver.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000230
231 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000232 __ JumpIfSmi(receiver, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000233
234 // Get the map of the receiver.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000235 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000236
237 // Check bit field.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000238 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000239 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000240 __ j(not_zero, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000241 // Check that the object is some kind of JS object EXCEPT JS Value type.
242 // In the case that the object is a value-wrapper object,
243 // we enter the runtime system to make sure that indexing
244 // into string objects works as intended.
245 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
246
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000247 __ CmpInstanceType(map, JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000248 __ j(below, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000249}
250
251
252// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000253// If not_fast_array is NULL, doesn't perform the elements map check.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000254static void GenerateFastArrayLoad(MacroAssembler* masm,
255 Register receiver,
256 Register key,
257 Register scratch,
258 Register result,
259 Label* not_fast_array,
260 Label* out_of_range) {
261 // Register use:
262 // receiver - holds the receiver and is unchanged.
263 // key - holds the key and is unchanged (must be a smi).
264 // Scratch registers:
265 // scratch - used to hold elements of the receiver and the loaded value.
266 // result - holds the result on exit if the load succeeds and
267 // we fall through.
268
269 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000270 if (not_fast_array != NULL) {
271 // Check that the object is in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000272 __ CheckMap(scratch,
273 FACTORY->fixed_array_map(),
274 not_fast_array,
275 DONT_DO_SMI_CHECK);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000276 } else {
277 __ AssertFastElements(scratch);
278 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000279 // Check that the key (index) is within bounds.
280 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
281 __ j(above_equal, out_of_range);
282 // Fast case: Do the load.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000283 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000284 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000285 __ cmp(scratch, Immediate(FACTORY->the_hole_value()));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000286 // In case the loaded value is the_hole we have to consult GetProperty
287 // to ensure the prototype chain is searched.
288 __ j(equal, out_of_range);
289 if (!result.is(scratch)) {
290 __ mov(result, scratch);
291 }
292}
293
294
ulan@chromium.org750145a2013-03-07 15:14:13 +0000295// Checks whether a key is an array index string or a unique name.
296// Falls through if the key is a unique name.
297static void GenerateKeyNameCheck(MacroAssembler* masm,
298 Register key,
299 Register map,
300 Register hash,
301 Label* index_string,
302 Label* not_unique) {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000303 // Register use:
304 // key - holds the key and is unchanged. Assumed to be non-smi.
305 // Scratch registers:
306 // map - used to hold the map of the key.
307 // hash - used to hold the hash of the key.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000308 Label unique;
309 __ CmpObjectType(key, LAST_UNIQUE_NAME_TYPE, map);
310 __ j(above, not_unique);
311 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
312 __ j(equal, &unique);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000313
314 // Is the string an array index, with cached numeric value?
ulan@chromium.org750145a2013-03-07 15:14:13 +0000315 __ mov(hash, FieldOperand(key, Name::kHashFieldOffset));
316 __ test(hash, Immediate(Name::kContainsCachedArrayIndexMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000317 __ j(zero, index_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000318
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000319 // Is the string internalized?
320 STATIC_ASSERT(kInternalizedTag != 0);
321 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsInternalizedMask);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000322 __ j(zero, not_unique);
323
324 __ bind(&unique);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000325}
326
327
whesse@chromium.org7b260152011-06-20 15:33:18 +0000328static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
329 Register object,
330 Register key,
331 Register scratch1,
332 Register scratch2,
333 Label* unmapped_case,
334 Label* slow_case) {
335 Heap* heap = masm->isolate()->heap();
336 Factory* factory = masm->isolate()->factory();
337
ager@chromium.org04921a82011-06-27 13:21:41 +0000338 // Check that the receiver is a JSObject. Because of the elements
339 // map check later, we do not need to check for interceptors or
340 // whether it requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000341 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +0000342 // Check that the object is some kind of JSObject.
343 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
344 __ j(below, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000345
346 // Check that the key is a positive smi.
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000347 __ test(key, Immediate(0x80000001));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000348 __ j(not_zero, slow_case);
349
350 // Load the elements into scratch1 and check its map.
351 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
352 __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
353 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
354
355 // Check if element is in the range of mapped arguments. If not, jump
356 // to the unmapped lookup with the parameter map in scratch1.
357 __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000358 __ sub(scratch2, Immediate(Smi::FromInt(2)));
359 __ cmp(key, scratch2);
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000360 __ j(above_equal, unmapped_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000361
362 // Load element index and check whether it is the hole.
363 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
364 __ mov(scratch2, FieldOperand(scratch1,
365 key,
366 times_half_pointer_size,
367 kHeaderSize));
368 __ cmp(scratch2, factory->the_hole_value());
369 __ j(equal, unmapped_case);
370
371 // Load value from context and return it. We can reuse scratch1 because
372 // we do not jump to the unmapped lookup (which requires the parameter
373 // map in scratch1).
374 const int kContextOffset = FixedArray::kHeaderSize;
375 __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
376 return FieldOperand(scratch1,
377 scratch2,
378 times_half_pointer_size,
379 Context::kHeaderSize);
380}
381
382
383static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
384 Register key,
385 Register parameter_map,
386 Register scratch,
387 Label* slow_case) {
388 // Element is in arguments backing store, which is referenced by the
389 // second element of the parameter_map.
390 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
391 Register backing_store = parameter_map;
392 __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000393 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
394 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000395 __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000396 __ cmp(key, scratch);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000397 __ j(greater_equal, slow_case);
398 return FieldOperand(backing_store,
399 key,
400 times_half_pointer_size,
401 FixedArray::kHeaderSize);
402}
403
404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
406 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000407 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +0000408 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 // -----------------------------------
ulan@chromium.org750145a2013-03-07 15:14:13 +0000411 Label slow, check_name, index_smi, index_name, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000412 Label probe_dictionary, check_number_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000415 __ JumpIfNotSmi(ecx, &check_name);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000416 __ bind(&index_smi);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000417 // Now the key is known to be a smi. This place is also jumped to from
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000418 // where a numeric string is converted to a smi.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000419
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000420 GenerateKeyedLoadReceiverCheck(
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000421 masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000422
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000423 // Check the receiver's map to see if it has fast elements.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000424 __ CheckFastElements(eax, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000425
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000426 GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000427 Isolate* isolate = masm->isolate();
428 Counters* counters = isolate->counters();
429 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000430 __ ret(0);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000431
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000432 __ bind(&check_number_dictionary);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000433 __ mov(ebx, ecx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000434 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000435 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000436
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000437 // Check whether the elements is a number dictionary.
438 // edx: receiver
439 // ebx: untagged index
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000440 // ecx: key
441 // eax: elements
442 __ CheckMap(eax,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000443 isolate->factory()->hash_table_map(),
444 &slow,
445 DONT_DO_SMI_CHECK);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000446 Label slow_pop_receiver;
447 // Push receiver on the stack to free up a register for the dictionary
448 // probing.
449 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000450 __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000451 // Pop receiver before returning.
452 __ pop(edx);
453 __ ret(0);
454
455 __ bind(&slow_pop_receiver);
456 // Pop the receiver from the stack and jump to runtime.
457 __ pop(edx);
458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 __ bind(&slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000460 // Slow case: jump to runtime.
461 // edx: receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000462 // ecx: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000463 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000464 GenerateRuntimeGetProperty(masm);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000465
ulan@chromium.org750145a2013-03-07 15:14:13 +0000466 __ bind(&check_name);
467 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000468
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000469 GenerateKeyedLoadReceiverCheck(
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000470 masm, edx, eax, Map::kHasNamedInterceptor, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000471
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000472 // If the receiver is a fast-case object, check the keyed lookup
ager@chromium.org5c838252010-02-19 08:53:10 +0000473 // cache. Otherwise probe the dictionary.
474 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000475 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000476 Immediate(isolate->factory()->hash_table_map()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000477 __ j(equal, &probe_dictionary);
478
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000479 // The receiver's map is still in eax, compute the keyed lookup cache hash
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000480 // based on 32 bits of the map pointer and the string hash.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000481 if (FLAG_debug_code) {
482 __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
483 __ Check(equal, "Map is no longer in eax.");
484 }
485 __ mov(ebx, eax); // Keep the map around for later.
486 __ shr(eax, KeyedLookupCache::kMapHashShift);
487 __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000488 __ shr(edi, String::kHashShift);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000489 __ xor_(eax, edi);
490 __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000491
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000492 // Load the key (consisting of map and internalized string) from the cache and
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000493 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000494 Label load_in_object_property;
495 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
496 Label hit_on_nth_entry[kEntriesPerBucket];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000497 ExternalReference cache_keys =
498 ExternalReference::keyed_lookup_cache_keys(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000499
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000500 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
501 Label try_next_entry;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000502 __ mov(edi, eax);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000503 __ shl(edi, kPointerSizeLog2 + 1);
504 if (i != 0) {
505 __ add(edi, Immediate(kPointerSize * i * 2));
506 }
507 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
508 __ j(not_equal, &try_next_entry);
509 __ add(edi, Immediate(kPointerSize));
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000510 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000511 __ j(equal, &hit_on_nth_entry[i]);
512 __ bind(&try_next_entry);
513 }
514
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000515 __ lea(edi, Operand(eax, 1));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000516 __ shl(edi, kPointerSizeLog2 + 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000517 __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000518 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519 __ j(not_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000520 __ add(edi, Immediate(kPointerSize));
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000521 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522 __ j(not_equal, &slow);
523
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000524 // Get field offset.
ager@chromium.org5c838252010-02-19 08:53:10 +0000525 // edx : receiver
526 // ebx : receiver's map
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000527 // ecx : key
528 // eax : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000529 ExternalReference cache_field_offsets =
530 ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000531
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000532 // Hit on nth entry.
533 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
534 __ bind(&hit_on_nth_entry[i]);
535 if (i != 0) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000536 __ add(eax, Immediate(i));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000537 }
538 __ mov(edi,
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000539 Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
540 __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
541 __ sub(edi, eax);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000542 __ j(above_equal, &property_array_property);
543 if (i != 0) {
544 __ jmp(&load_in_object_property);
545 }
546 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000547
548 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000549 __ bind(&load_in_object_property);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000550 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
551 __ add(eax, edi);
552 __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000553 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554 __ ret(0);
555
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000556 // Load property array property.
557 __ bind(&property_array_property);
558 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
559 __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
560 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000561 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000562 __ ret(0);
563
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564 // Do a quick inline probe of the receiver's dictionary, if it
565 // exists.
566 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000567
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000568 __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
569 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
570 GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000571
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000572 GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000573 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 __ ret(0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575
ulan@chromium.org750145a2013-03-07 15:14:13 +0000576 __ bind(&index_name);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000577 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000578 // Now jump to the place where smi keys are handled.
579 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580}
581
582
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000583void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
584 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000585 // -- ecx : key (index)
ager@chromium.org5c838252010-02-19 08:53:10 +0000586 // -- edx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000587 // -- esp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000588 // -----------------------------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000589 Label miss;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000590
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000591 Register receiver = edx;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000592 Register index = ecx;
593 Register scratch = ebx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000594 Register result = eax;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000595
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000596 StringCharAtGenerator char_at_generator(receiver,
597 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000598 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000599 result,
600 &miss, // When not a string.
601 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000602 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000603 STRING_INDEX_IS_ARRAY_INDEX);
604 char_at_generator.GenerateFast(masm);
605 __ ret(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000606
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000607 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000608 char_at_generator.GenerateSlow(masm, call_helper);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000609
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000610 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000611 GenerateMiss(masm, MISS);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000612}
613
614
ager@chromium.org5c838252010-02-19 08:53:10 +0000615void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
616 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000617 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +0000618 // -- edx : receiver
619 // -- esp[0] : return address
620 // -----------------------------------
621 Label slow;
622
623 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000624 __ JumpIfSmi(edx, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000625
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000626 // Check that the key is an array index, that is Uint32.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000627 __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000628 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000629
630 // Get the map of the receiver.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000631 __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000632
633 // Check that it has indexed interceptor and access checks
634 // are not enabled for this object.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000635 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
636 __ and_(eax, Immediate(kSlowCaseBitFieldMask));
637 __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000638 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000639
640 // Everything is fine, call runtime.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000641 __ pop(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +0000642 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000643 __ push(ecx); // key
644 __ push(eax); // return address
ager@chromium.org5c838252010-02-19 08:53:10 +0000645
646 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 ExternalReference ref =
648 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
649 masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000650 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000651
652 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000653 GenerateMiss(masm, MISS);
ager@chromium.org3811b432009-10-28 14:53:37 +0000654}
655
656
whesse@chromium.org7b260152011-06-20 15:33:18 +0000657void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
658 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000659 // -- ecx : key
whesse@chromium.org7b260152011-06-20 15:33:18 +0000660 // -- edx : receiver
661 // -- esp[0] : return address
662 // -----------------------------------
663 Label slow, notin;
664 Factory* factory = masm->isolate()->factory();
665 Operand mapped_location =
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000666 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000667 __ mov(eax, mapped_location);
668 __ Ret();
669 __ bind(&notin);
670 // The unmapped lookup expects that the parameter map is in ebx.
671 Operand unmapped_location =
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000672 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000673 __ cmp(unmapped_location, factory->the_hole_value());
674 __ j(equal, &slow);
675 __ mov(eax, unmapped_location);
676 __ Ret();
677 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000678 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000679}
680
681
682void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
683 // ----------- S t a t e -------------
684 // -- eax : value
685 // -- ecx : key
686 // -- edx : receiver
687 // -- esp[0] : return address
688 // -----------------------------------
689 Label slow, notin;
690 Operand mapped_location =
691 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, &notin, &slow);
692 __ mov(mapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000693 __ lea(ecx, mapped_location);
694 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000696 __ Ret();
697 __ bind(&notin);
698 // The unmapped lookup expects that the parameter map is in ebx.
699 Operand unmapped_location =
700 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
701 __ mov(unmapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000702 __ lea(edi, unmapped_location);
703 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000704 __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000705 __ Ret();
706 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000707 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000708}
709
710
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000711static void KeyedStoreGenerateGenericHelper(
712 MacroAssembler* masm,
713 Label* fast_object,
714 Label* fast_double,
715 Label* slow,
716 KeyedStoreCheckMap check_map,
717 KeyedStoreIncrementLength increment_length) {
718 Label transition_smi_elements;
719 Label finish_object_store, non_double_value, transition_double_elements;
720 Label fast_double_without_map_check;
721 // eax: value
722 // ecx: key (a smi)
723 // edx: receiver
724 // ebx: FixedArray receiver->elements
725 // edi: receiver map
726 // Fast case: Do the store, could either Object or double.
727 __ bind(fast_object);
728 if (check_map == kCheckMap) {
729 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
730 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
731 __ j(not_equal, fast_double);
732 }
733 // Smi stores don't require further checks.
734 Label non_smi_value;
735 __ JumpIfNotSmi(eax, &non_smi_value);
736 if (increment_length == kIncrementLength) {
737 // Add 1 to receiver->length.
738 __ add(FieldOperand(edx, JSArray::kLengthOffset),
739 Immediate(Smi::FromInt(1)));
740 }
741 // It's irrelevant whether array is smi-only or not when writing a smi.
742 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
743 __ ret(0);
744
745 __ bind(&non_smi_value);
746 // Escape to elements kind transition case.
747 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
748 __ CheckFastObjectElements(edi, &transition_smi_elements);
749
750 // Fast elements array, store the value to the elements backing store.
751 __ bind(&finish_object_store);
752 if (increment_length == kIncrementLength) {
753 // Add 1 to receiver->length.
754 __ add(FieldOperand(edx, JSArray::kLengthOffset),
755 Immediate(Smi::FromInt(1)));
756 }
757 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
758 // Update write barrier for the elements array address.
759 __ mov(edx, eax); // Preserve the value which is returned.
760 __ RecordWriteArray(
761 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
762 __ ret(0);
763
764 __ bind(fast_double);
765 if (check_map == kCheckMap) {
766 // Check for fast double array case. If this fails, call through to the
767 // runtime.
768 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
769 __ j(not_equal, slow);
770 // If the value is a number, store it as a double in the FastDoubleElements
771 // array.
772 }
773 __ bind(&fast_double_without_map_check);
774 __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
775 &transition_double_elements, false);
776 if (increment_length == kIncrementLength) {
777 // Add 1 to receiver->length.
778 __ add(FieldOperand(edx, JSArray::kLengthOffset),
779 Immediate(Smi::FromInt(1)));
780 }
781 __ ret(0);
782
783 __ bind(&transition_smi_elements);
784 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
785
786 // Transition the array appropriately depending on the value type.
787 __ CheckMap(eax,
788 masm->isolate()->factory()->heap_number_map(),
789 &non_double_value,
790 DONT_DO_SMI_CHECK);
791
792 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
793 // and complete the store.
794 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
795 FAST_DOUBLE_ELEMENTS,
796 ebx,
797 edi,
798 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000799 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
800 FAST_DOUBLE_ELEMENTS);
801 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000802 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
803 __ jmp(&fast_double_without_map_check);
804
805 __ bind(&non_double_value);
806 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
807 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
808 FAST_ELEMENTS,
809 ebx,
810 edi,
811 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000812 mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
813 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
814 slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000815 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
816 __ jmp(&finish_object_store);
817
818 __ bind(&transition_double_elements);
819 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
820 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
821 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
822 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
823 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
824 FAST_ELEMENTS,
825 ebx,
826 edi,
827 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000828 mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
829 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000830 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
831 __ jmp(&finish_object_store);
832}
833
834
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000835void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
836 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837 // ----------- S t a t e -------------
838 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000839 // -- ecx : key
840 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 // -----------------------------------
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000843 Label slow, fast_object, fast_object_grow;
844 Label fast_double, fast_double_grow;
845 Label array, extra, check_if_double_array;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000846
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000848 __ JumpIfSmi(edx, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000849 // Get the map from the receiver.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000850 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000851 // Check that the receiver does not require access checks. We need
852 // to do this because this generic stub does not perform map checks.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000853 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
854 1 << Map::kIsAccessCheckNeeded);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000855 __ j(not_zero, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000856 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000857 __ JumpIfNotSmi(ecx, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000858 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000860 // Check that the object is some kind of JSObject.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000861 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000862 __ j(below, &slow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000864 // Object case: Check key against length in the elements array.
865 // eax: value
866 // edx: JSObject
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000867 // ecx: key (a smi)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000868 // edi: receiver map
869 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
870 // Check array bounds. Both the key and the length of FixedArray are smis.
871 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000872 __ j(below, &fast_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873
ager@chromium.org3811b432009-10-28 14:53:37 +0000874 // Slow case: call runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875 __ bind(&slow);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000876 GenerateRuntimeSetProperty(masm, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 // Extra capacity case: Check if there is extra capacity to
879 // perform the store and update the length. Used for adding one
880 // element to the array by writing to array[array.length].
881 __ bind(&extra);
882 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000883 // edx: receiver, a JSArray
884 // ecx: key, a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000885 // ebx: receiver->elements, a FixedArray
886 // edi: receiver map
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000887 // flags: compare (ecx, edx.length())
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000888 // do not leave holes in the array:
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000889 __ j(not_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000890 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000891 __ j(above_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000892 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
893 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
894 __ j(not_equal, &check_if_double_array);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000895 __ jmp(&fast_object_grow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000896
897 __ bind(&check_if_double_array);
898 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
899 __ j(not_equal, &slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000900 __ jmp(&fast_double_grow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000903 // array. Check that the array is in fast mode (and writable); if it
904 // is the length is always a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905 __ bind(&array);
906 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000907 // edx: receiver, a JSArray
908 // ecx: key, a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000909 // edi: receiver map
910 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000912 // Check the key against the length in the array and fall through to the
913 // common store code.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000914 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000915 __ j(above_equal, &extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000917 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
918 &slow, kCheckMap, kDontIncrementLength);
919 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
920 &slow, kDontCheckMap, kIncrementLength);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921}
922
923
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000924// The generated code does not accept smi keys.
925// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000926void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
927 int argc,
928 Code::Kind kind,
929 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000931 // -- ecx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000932 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000934 Label number, non_number, non_string, boolean, probe, miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000935
936 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000937 Code::Flags flags = Code::ComputeFlags(kind,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000938 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000939 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000940 Code::NORMAL,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000941 argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000942 Isolate* isolate = masm->isolate();
943 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944
945 // If the stub cache probing failed, the receiver might be a value.
946 // For value objects, we use the map of the prototype objects for
947 // the corresponding JSValue for the cache and that is what we need
948 // to probe.
949 //
950 // Check for number.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000951 __ JumpIfSmi(edx, &number);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000952 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000953 __ j(not_equal, &non_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954 __ bind(&number);
955 StubCompiler::GenerateLoadGlobalFunctionPrototype(
956 masm, Context::NUMBER_FUNCTION_INDEX, edx);
957 __ jmp(&probe);
958
959 // Check for string.
960 __ bind(&non_number);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000961 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000962 __ j(above_equal, &non_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000963 StubCompiler::GenerateLoadGlobalFunctionPrototype(
964 masm, Context::STRING_FUNCTION_INDEX, edx);
965 __ jmp(&probe);
966
967 // Check for boolean.
968 __ bind(&non_string);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000969 __ cmp(edx, isolate->factory()->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000970 __ j(equal, &boolean);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000971 __ cmp(edx, isolate->factory()->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000972 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000973 __ bind(&boolean);
974 StubCompiler::GenerateLoadGlobalFunctionPrototype(
975 masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
976
977 // Probe the stub cache for the value object.
978 __ bind(&probe);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000979 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000980 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981}
982
983
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000984static void GenerateFunctionTailCall(MacroAssembler* masm,
985 int argc,
986 Label* miss) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000987 // ----------- S t a t e -------------
988 // -- ecx : name
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000989 // -- edi : function
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000990 // -- esp[0] : return address
991 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
992 // -- ...
993 // -- esp[(argc + 1) * 4] : receiver
994 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000995
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000996 // Check that the result is not a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000997 __ JumpIfSmi(edi, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000998
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000999 // Check that the value is a JavaScript function, fetching its map into eax.
1000 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001001 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001002
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001003 // Invoke the function.
1004 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001005 __ InvokeFunction(edi, actual, JUMP_FUNCTION,
1006 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001007}
1008
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001009
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001010// The generated code falls through if the call should be handled by runtime.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001011void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001012 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001013 // -- ecx : name
1014 // -- esp[0] : return address
1015 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1016 // -- ...
1017 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001019 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020
1021 // Get the receiver of the function from the stack; 1 ~ return address.
1022 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023
ulan@chromium.org750145a2013-03-07 15:14:13 +00001024 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001025
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001026 // eax: elements
1027 // Search the dictionary placing the result in edi.
1028 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
1029 GenerateFunctionTailCall(masm, argc, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001030
1031 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032}
1033
1034
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001035void CallICBase::GenerateMiss(MacroAssembler* masm,
1036 int argc,
1037 IC::UtilityId id,
1038 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001040 // -- ecx : name
1041 // -- esp[0] : return address
1042 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1043 // -- ...
1044 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045 // -----------------------------------
1046
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001047 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001048 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001049 __ IncrementCounter(counters->call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001050 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001051 __ IncrementCounter(counters->keyed_call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001052 }
1053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 // Get the receiver of the function from the stack; 1 ~ return address.
1055 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001057 {
1058 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001060 // Push the receiver and the name of the function.
1061 __ push(edx);
1062 __ push(ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001064 // Call the entry.
1065 CEntryStub stub(1);
1066 __ mov(eax, Immediate(2));
1067 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
1068 __ CallStub(&stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001070 // Move result to edi and exit the internal frame.
1071 __ mov(edi, eax);
1072 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001074 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001075 // This can happen only for regular CallIC but not KeyedCallIC.
1076 if (id == IC::kCallIC_Miss) {
1077 Label invoke, global;
1078 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
whesse@chromium.org7b260152011-06-20 15:33:18 +00001079 __ JumpIfSmi(edx, &invoke, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001080 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1081 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1082 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001083 __ j(equal, &global, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001084 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001085 __ j(not_equal, &invoke, Label::kNear);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001086
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001087 // Patch the receiver on the stack.
1088 __ bind(&global);
1089 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1090 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1091 __ bind(&invoke);
1092 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001093
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001094 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001095 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +00001096 ? CALL_AS_FUNCTION
1097 : CALL_AS_METHOD;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001099 __ InvokeFunction(edi,
1100 actual,
1101 JUMP_FUNCTION,
1102 NullCallWrapper(),
1103 call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104}
1105
1106
danno@chromium.org40cb8782011-05-25 07:58:50 +00001107void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1108 int argc,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001109 Code::ExtraICState extra_state) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001110 // ----------- S t a t e -------------
1111 // -- ecx : name
1112 // -- esp[0] : return address
1113 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1114 // -- ...
1115 // -- esp[(argc + 1) * 4] : receiver
1116 // -----------------------------------
1117
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001118 // Get the receiver of the function from the stack; 1 ~ return address.
1119 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001120 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
1121 extra_state);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001122
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001123 GenerateMiss(masm, argc, extra_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001124}
1125
1126
1127void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1128 // ----------- S t a t e -------------
1129 // -- ecx : name
1130 // -- esp[0] : return address
1131 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1132 // -- ...
1133 // -- esp[(argc + 1) * 4] : receiver
1134 // -----------------------------------
1135
1136 // Get the receiver of the function from the stack; 1 ~ return address.
1137 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1138
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001139 Label do_call, slow_call, slow_load, slow_reload_receiver;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001140 Label check_number_dictionary, check_name, lookup_monomorphic_cache;
1141 Label index_smi, index_name;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001142
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001143 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +00001144 __ JumpIfNotSmi(ecx, &check_name);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001145
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001146 __ bind(&index_smi);
1147 // Now the key is known to be a smi. This place is also jumped to from
1148 // where a numeric string is converted to a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001149
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001150 GenerateKeyedLoadReceiverCheck(
1151 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001152
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001153 GenerateFastArrayLoad(
1154 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001155 Isolate* isolate = masm->isolate();
1156 Counters* counters = isolate->counters();
1157 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001158
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001159 __ bind(&do_call);
1160 // receiver in edx is not used after this point.
1161 // ecx: key
1162 // edi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001163 GenerateFunctionTailCall(masm, argc, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001164
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001165 __ bind(&check_number_dictionary);
1166 // eax: elements
1167 // ecx: smi key
1168 // Check whether the elements is a number dictionary.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001169 __ CheckMap(eax,
1170 isolate->factory()->hash_table_map(),
1171 &slow_load,
1172 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001173 __ mov(ebx, ecx);
1174 __ SmiUntag(ebx);
1175 // ebx: untagged index
1176 // Receiver in edx will be clobbered, need to reload it on miss.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001177 __ LoadFromNumberDictionary(
1178 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001179 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001180 __ jmp(&do_call);
1181
1182 __ bind(&slow_reload_receiver);
1183 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1184
1185 __ bind(&slow_load);
1186 // This branch is taken when calling KeyedCallIC_Miss is neither required
1187 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001188 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001189
1190 {
1191 FrameScope scope(masm, StackFrame::INTERNAL);
1192 __ push(ecx); // save the key
1193 __ push(edx); // pass the receiver
1194 __ push(ecx); // pass the key
1195 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1196 __ pop(ecx); // restore the key
1197 // Leave the internal frame.
1198 }
1199
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001200 __ mov(edi, eax);
1201 __ jmp(&do_call);
1202
ulan@chromium.org750145a2013-03-07 15:14:13 +00001203 __ bind(&check_name);
1204 GenerateKeyNameCheck(masm, ecx, eax, ebx, &index_name, &slow_call);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001205
ulan@chromium.org750145a2013-03-07 15:14:13 +00001206 // The key is known to be a unique name.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001207 // If the receiver is a regular JS object with slow properties then do
1208 // a quick inline probe of the receiver's dictionary.
1209 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001210 GenerateKeyedLoadReceiverCheck(
1211 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001212
1213 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001214 __ CheckMap(ebx,
1215 isolate->factory()->hash_table_map(),
1216 &lookup_monomorphic_cache,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001217 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001218
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001219 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001220 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001221 __ jmp(&do_call);
1222
1223 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001224 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001225 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
1226 Code::kNoExtraICState);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001227 // Fall through on miss.
1228
1229 __ bind(&slow_call);
1230 // This branch is taken if:
1231 // - the receiver requires boxing or access check,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001232 // - the key is neither smi nor a unique name,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001233 // - the value loaded is not a function,
1234 // - there is hope that the runtime will create a monomorphic call stub
1235 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001236 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001237 GenerateMiss(masm, argc);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001238
ulan@chromium.org750145a2013-03-07 15:14:13 +00001239 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001240 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001241 // Now jump to the place where smi keys are handled.
1242 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001243}
1244
1245
whesse@chromium.org7b260152011-06-20 15:33:18 +00001246void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1247 int argc) {
1248 // ----------- S t a t e -------------
1249 // -- ecx : name
1250 // -- esp[0] : return address
1251 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1252 // -- ...
1253 // -- esp[(argc + 1) * 4] : receiver
1254 // -----------------------------------
1255 Label slow, notin;
1256 Factory* factory = masm->isolate()->factory();
1257 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1258 Operand mapped_location =
1259 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
1260 __ mov(edi, mapped_location);
1261 GenerateFunctionTailCall(masm, argc, &slow);
1262 __ bind(&notin);
1263 // The unmapped lookup expects that the parameter map is in ebx.
1264 Operand unmapped_location =
1265 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
1266 __ cmp(unmapped_location, factory->the_hole_value());
1267 __ j(equal, &slow);
1268 __ mov(edi, unmapped_location);
1269 GenerateFunctionTailCall(masm, argc, &slow);
1270 __ bind(&slow);
1271 GenerateMiss(masm, argc);
1272}
1273
1274
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001275void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001276 // ----------- S t a t e -------------
1277 // -- ecx : name
1278 // -- esp[0] : return address
1279 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1280 // -- ...
1281 // -- esp[(argc + 1) * 4] : receiver
1282 // -----------------------------------
1283
ulan@chromium.org750145a2013-03-07 15:14:13 +00001284 // Check if the name is really a name.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001285 Label miss;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001286 __ JumpIfSmi(ecx, &miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001287 Condition cond = masm->IsObjectNameType(ecx, eax, eax);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001288 __ j(NegateCondition(cond), &miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001289 CallICBase::GenerateNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001290 __ bind(&miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001291 GenerateMiss(masm, argc);
1292}
1293
1294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1296 // ----------- S t a t e -------------
1297 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001298 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001299 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 // -----------------------------------
1301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302 // Probe the stub cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001303 Code::Flags flags = Code::ComputeFlags(
ulan@chromium.org750145a2013-03-07 15:14:13 +00001304 Code::STUB, MONOMORPHIC, Code::kNoExtraICState,
1305 Code::NORMAL, Code::LOAD_IC);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001306 Isolate::Current()->stub_cache()->GenerateProbe(
1307 masm, flags, edx, ecx, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308
1309 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +00001310 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311}
1312
1313
1314void LoadIC::GenerateNormal(MacroAssembler* masm) {
1315 // ----------- S t a t e -------------
1316 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001317 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001320 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321
ulan@chromium.org750145a2013-03-07 15:14:13 +00001322 GenerateNameDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001324 // eax: elements
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 // Search the dictionary placing the result in eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001326 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 __ ret(0);
1328
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001329 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001331 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332}
1333
1334
1335void LoadIC::GenerateMiss(MacroAssembler* masm) {
1336 // ----------- S t a t e -------------
1337 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001338 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340 // -----------------------------------
1341
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001342 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 __ pop(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001345 __ push(edx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001346 __ push(ecx); // name
1347 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348
mads.s.ager31e71382008-08-13 09:32:07 +00001349 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 ExternalReference ref =
1351 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001352 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353}
1354
1355
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001356void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001358 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00001359 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 // -----------------------------------
1362
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001363 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001364
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 __ pop(ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001366 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001367 __ push(ecx); // name
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001368 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
mads.s.ager31e71382008-08-13 09:32:07 +00001370 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001371 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001372 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1373 masm->isolate())
1374 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001375 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001376}
1377
1378
1379void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1380 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001381 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00001382 // -- edx : receiver
1383 // -- esp[0] : return address
1384 // -----------------------------------
1385
1386 __ pop(ebx);
1387 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001388 __ push(ecx); // name
ager@chromium.org5c838252010-02-19 08:53:10 +00001389 __ push(ebx); // return address
1390
1391 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001392 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393}
1394
1395
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001396void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001397 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398 // ----------- S t a t e -------------
1399 // -- eax : value
1400 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001401 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 // -----------------------------------
1404
lrn@chromium.org34e60782011-09-15 07:25:40 +00001405 Code::Flags flags =
1406 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001407 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
1408 no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
1410 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001411 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412}
1413
1414
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001415void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001416 // ----------- S t a t e -------------
1417 // -- eax : value
1418 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001419 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421 // -----------------------------------
1422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 __ pop(ebx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001424 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 __ push(ecx);
1426 __ push(eax);
1427 __ push(ebx);
1428
mads.s.ager31e71382008-08-13 09:32:07 +00001429 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001430 ExternalReference ref =
1431 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001432 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433}
1434
1435
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001436void StoreIC::GenerateNormal(MacroAssembler* masm) {
1437 // ----------- S t a t e -------------
1438 // -- eax : value
1439 // -- ecx : name
1440 // -- edx : receiver
1441 // -- esp[0] : return address
1442 // -----------------------------------
1443
1444 Label miss, restore_miss;
1445
ulan@chromium.org750145a2013-03-07 15:14:13 +00001446 GenerateNameDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001447
1448 // A lot of registers are needed for storing to slow case
1449 // objects. Push and restore receiver but rely on
1450 // GenerateDictionaryStore preserving the value and name.
1451 __ push(edx);
1452 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1453 __ Drop(1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001454 Counters* counters = masm->isolate()->counters();
1455 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001456 __ ret(0);
1457
1458 __ bind(&restore_miss);
1459 __ pop(edx);
1460
1461 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001462 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001463 GenerateMiss(masm);
1464}
1465
1466
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1468 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001469 // ----------- S t a t e -------------
1470 // -- eax : value
1471 // -- ecx : name
1472 // -- edx : receiver
1473 // -- esp[0] : return address
1474 // -----------------------------------
1475 __ pop(ebx);
1476 __ push(edx);
1477 __ push(ecx);
1478 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1480 __ push(Immediate(Smi::FromInt(strict_mode)));
1481 __ push(ebx); // return address
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001482
1483 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001484 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001485}
1486
1487
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001488void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1489 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 // ----------- S t a t e -------------
1491 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001492 // -- ecx : key
1493 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495 // -----------------------------------
1496
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001497 __ pop(ebx);
1498 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001499 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001500 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001501 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1502 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode.
1503 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001504
1505 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507}
1508
1509
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001510void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001511 // ----------- S t a t e -------------
1512 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001513 // -- ecx : key
1514 // -- edx : receiver
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001515 // -- esp[0] : return address
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001516 // -----------------------------------
1517
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001518 __ pop(ebx);
1519 __ push(edx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001520 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001521 __ push(eax);
1522 __ push(ebx);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001523
1524 // Do tail-call to runtime routine.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001525 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001526 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1527 masm->isolate())
1528 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1529 __ TailCallExternalReference(ref, 3, 1);
1530}
1531
1532
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001533void StoreIC::GenerateSlow(MacroAssembler* masm) {
1534 // ----------- S t a t e -------------
1535 // -- eax : value
1536 // -- ecx : key
1537 // -- edx : receiver
1538 // -- esp[0] : return address
1539 // -----------------------------------
1540
1541 __ pop(ebx);
1542 __ push(edx);
1543 __ push(ecx);
1544 __ push(eax);
1545 __ push(ebx); // return address
1546
1547 // Do tail-call to runtime routine.
1548 ExternalReference ref(IC_Utility(kStoreIC_Slow), masm->isolate());
1549 __ TailCallExternalReference(ref, 3, 1);
1550}
1551
1552
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001553void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1554 // ----------- S t a t e -------------
1555 // -- eax : value
1556 // -- ecx : key
1557 // -- edx : receiver
1558 // -- esp[0] : return address
1559 // -----------------------------------
1560
1561 __ pop(ebx);
1562 __ push(edx);
1563 __ push(ecx);
1564 __ push(eax);
1565 __ push(ebx); // return address
1566
1567 // Do tail-call to runtime routine.
1568 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001569 __ TailCallExternalReference(ref, 3, 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001570}
1571
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001572
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001573void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1574 // ----------- S t a t e -------------
1575 // -- ebx : target map
1576 // -- edx : receiver
1577 // -- esp[0] : return address
1578 // -----------------------------------
1579 // Must return the modified receiver in eax.
1580 if (!FLAG_trace_elements_transitions) {
1581 Label fail;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001582 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1583 FAST_DOUBLE_ELEMENTS);
1584 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001585 __ mov(eax, edx);
1586 __ Ret();
1587 __ bind(&fail);
1588 }
1589
1590 __ pop(ebx);
1591 __ push(edx);
1592 __ push(ebx); // return address
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001593 // Leaving the code managed by the register allocator and return to the
1594 // convention of using esi as context register.
1595 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001596 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1597}
1598
1599
1600void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1601 MacroAssembler* masm) {
1602 // ----------- S t a t e -------------
1603 // -- ebx : target map
1604 // -- edx : receiver
1605 // -- esp[0] : return address
1606 // -----------------------------------
1607 // Must return the modified receiver in eax.
1608 if (!FLAG_trace_elements_transitions) {
1609 Label fail;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001610 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
1611 FAST_ELEMENTS);
1612 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001613 __ mov(eax, edx);
1614 __ Ret();
1615 __ bind(&fail);
1616 }
1617
1618 __ pop(ebx);
1619 __ push(edx);
1620 __ push(ebx); // return address
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001621 // Leaving the code managed by the register allocator and return to the
1622 // convention of using esi as context register.
1623 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001624 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1625}
1626
1627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628#undef __
1629
1630
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001631Condition CompareIC::ComputeCondition(Token::Value op) {
1632 switch (op) {
1633 case Token::EQ_STRICT:
1634 case Token::EQ:
1635 return equal;
1636 case Token::LT:
1637 return less;
1638 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001639 return greater;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001640 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001641 return less_equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001642 case Token::GTE:
1643 return greater_equal;
1644 default:
1645 UNREACHABLE();
1646 return no_condition;
1647 }
1648}
1649
1650
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001651bool CompareIC::HasInlinedSmiCode(Address address) {
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 return *test_instruction_address == Assembler::kTestAlByte;
1659}
1660
1661
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001662void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001663 // The address of the instruction following the call.
1664 Address test_instruction_address =
1665 address + Assembler::kCallTargetAddressOffset;
1666
1667 // If the instruction following the call is not a test al, nothing
1668 // was inlined.
1669 if (*test_instruction_address != Assembler::kTestAlByte) {
1670 ASSERT(*test_instruction_address == Assembler::kNopByte);
1671 return;
1672 }
1673
1674 Address delta_address = test_instruction_address + 1;
1675 // The delta to the start of the map check instruction and the
1676 // condition code uses at the patched jump.
1677 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1678 if (FLAG_trace_ic) {
1679 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1680 address, test_instruction_address, delta);
1681 }
1682
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001683 // Patch with a short conditional jump. Enabling means switching from a short
1684 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
1685 // reverse operation of that.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001686 Address jmp_address = test_instruction_address - delta;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001687 ASSERT((check == ENABLE_INLINED_SMI_CHECK)
1688 ? (*jmp_address == Assembler::kJncShortOpcode ||
1689 *jmp_address == Assembler::kJcShortOpcode)
1690 : (*jmp_address == Assembler::kJnzShortOpcode ||
1691 *jmp_address == Assembler::kJzShortOpcode));
1692 Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1693 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1694 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001695 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001696}
1697
1698
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001700
1701#endif // V8_TARGET_ARCH_IA32