blob: 428d8307027d2fe4f1318c63142b76d3af9f35f6 [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.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000063static void GenerateStringDictionaryReceiverCheck(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.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000130 StringDictionaryLookupStub::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 =
143 StringDictionary::kHeaderSize +
144 StringDictionary::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.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000185 StringDictionaryLookupStub::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 =
198 StringDictionary::kHeaderSize +
199 StringDictionary::kElementsStartIndex * kPointerSize;
200 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
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000295// Checks whether a key is an array index string or an internalized string.
296// Falls through if the key is an internalized string.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000297static void GenerateKeyStringCheck(MacroAssembler* masm,
298 Register key,
299 Register map,
300 Register hash,
301 Label* index_string,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000302 Label* not_internalized) {
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.
308 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000309 __ j(above_equal, not_internalized);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000310
311 // Is the string an array index, with cached numeric value?
312 __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
313 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000314 __ j(zero, index_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000315
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000316 // Is the string internalized?
317 STATIC_ASSERT(kInternalizedTag != 0);
318 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsInternalizedMask);
319 __ j(zero, not_internalized);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000320}
321
322
whesse@chromium.org7b260152011-06-20 15:33:18 +0000323static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
324 Register object,
325 Register key,
326 Register scratch1,
327 Register scratch2,
328 Label* unmapped_case,
329 Label* slow_case) {
330 Heap* heap = masm->isolate()->heap();
331 Factory* factory = masm->isolate()->factory();
332
ager@chromium.org04921a82011-06-27 13:21:41 +0000333 // Check that the receiver is a JSObject. Because of the elements
334 // map check later, we do not need to check for interceptors or
335 // whether it requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000336 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +0000337 // Check that the object is some kind of JSObject.
338 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
339 __ j(below, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000340
341 // Check that the key is a positive smi.
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000342 __ test(key, Immediate(0x80000001));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000343 __ j(not_zero, slow_case);
344
345 // Load the elements into scratch1 and check its map.
346 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
347 __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
348 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
349
350 // Check if element is in the range of mapped arguments. If not, jump
351 // to the unmapped lookup with the parameter map in scratch1.
352 __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000353 __ sub(scratch2, Immediate(Smi::FromInt(2)));
354 __ cmp(key, scratch2);
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000355 __ j(above_equal, unmapped_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000356
357 // Load element index and check whether it is the hole.
358 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
359 __ mov(scratch2, FieldOperand(scratch1,
360 key,
361 times_half_pointer_size,
362 kHeaderSize));
363 __ cmp(scratch2, factory->the_hole_value());
364 __ j(equal, unmapped_case);
365
366 // Load value from context and return it. We can reuse scratch1 because
367 // we do not jump to the unmapped lookup (which requires the parameter
368 // map in scratch1).
369 const int kContextOffset = FixedArray::kHeaderSize;
370 __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
371 return FieldOperand(scratch1,
372 scratch2,
373 times_half_pointer_size,
374 Context::kHeaderSize);
375}
376
377
378static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
379 Register key,
380 Register parameter_map,
381 Register scratch,
382 Label* slow_case) {
383 // Element is in arguments backing store, which is referenced by the
384 // second element of the parameter_map.
385 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
386 Register backing_store = parameter_map;
387 __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000388 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
389 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000390 __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000391 __ cmp(key, scratch);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000392 __ j(greater_equal, slow_case);
393 return FieldOperand(backing_store,
394 key,
395 times_half_pointer_size,
396 FixedArray::kHeaderSize);
397}
398
399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
401 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000402 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +0000403 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 // -----------------------------------
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000406 Label slow, check_string, index_smi, index_string, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000407 Label probe_dictionary, check_number_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 // Check that the key is a smi.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000410 __ JumpIfNotSmi(ecx, &check_string);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000411 __ bind(&index_smi);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000412 // Now the key is known to be a smi. This place is also jumped to from
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000413 // where a numeric string is converted to a smi.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000414
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000415 GenerateKeyedLoadReceiverCheck(
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000416 masm, edx, eax, Map::kHasIndexedInterceptor, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000417
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000418 // Check the receiver's map to see if it has fast elements.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000419 __ CheckFastElements(eax, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000421 GenerateFastArrayLoad(masm, edx, ecx, eax, eax, NULL, &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000422 Isolate* isolate = masm->isolate();
423 Counters* counters = isolate->counters();
424 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000425 __ ret(0);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000426
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000427 __ bind(&check_number_dictionary);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000428 __ mov(ebx, ecx);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000429 __ SmiUntag(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000430 __ mov(eax, FieldOperand(edx, JSObject::kElementsOffset));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000431
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000432 // Check whether the elements is a number dictionary.
433 // edx: receiver
434 // ebx: untagged index
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000435 // ecx: key
436 // eax: elements
437 __ CheckMap(eax,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000438 isolate->factory()->hash_table_map(),
439 &slow,
440 DONT_DO_SMI_CHECK);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000441 Label slow_pop_receiver;
442 // Push receiver on the stack to free up a register for the dictionary
443 // probing.
444 __ push(edx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000445 __ LoadFromNumberDictionary(&slow_pop_receiver, eax, ecx, ebx, edx, edi, eax);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000446 // Pop receiver before returning.
447 __ pop(edx);
448 __ ret(0);
449
450 __ bind(&slow_pop_receiver);
451 // Pop the receiver from the stack and jump to runtime.
452 __ pop(edx);
453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454 __ bind(&slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000455 // Slow case: jump to runtime.
456 // edx: receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000457 // ecx: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000458 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 GenerateRuntimeGetProperty(masm);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461 __ bind(&check_string);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000462 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000463
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000464 GenerateKeyedLoadReceiverCheck(
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000465 masm, edx, eax, Map::kHasNamedInterceptor, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000466
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000467 // If the receiver is a fast-case object, check the keyed lookup
ager@chromium.org5c838252010-02-19 08:53:10 +0000468 // cache. Otherwise probe the dictionary.
469 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000470 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000471 Immediate(isolate->factory()->hash_table_map()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000472 __ j(equal, &probe_dictionary);
473
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000474 // The receiver's map is still in eax, compute the keyed lookup cache hash
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000475 // based on 32 bits of the map pointer and the string hash.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000476 if (FLAG_debug_code) {
477 __ cmp(eax, FieldOperand(edx, HeapObject::kMapOffset));
478 __ Check(equal, "Map is no longer in eax.");
479 }
480 __ mov(ebx, eax); // Keep the map around for later.
481 __ shr(eax, KeyedLookupCache::kMapHashShift);
482 __ mov(edi, FieldOperand(ecx, String::kHashFieldOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000483 __ shr(edi, String::kHashShift);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000484 __ xor_(eax, edi);
485 __ and_(eax, KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000486
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000487 // Load the key (consisting of map and internalized string) from the cache and
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000488 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000489 Label load_in_object_property;
490 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
491 Label hit_on_nth_entry[kEntriesPerBucket];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000492 ExternalReference cache_keys =
493 ExternalReference::keyed_lookup_cache_keys(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000494
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000495 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
496 Label try_next_entry;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000497 __ mov(edi, eax);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000498 __ shl(edi, kPointerSizeLog2 + 1);
499 if (i != 0) {
500 __ add(edi, Immediate(kPointerSize * i * 2));
501 }
502 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
503 __ j(not_equal, &try_next_entry);
504 __ add(edi, Immediate(kPointerSize));
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000505 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000506 __ j(equal, &hit_on_nth_entry[i]);
507 __ bind(&try_next_entry);
508 }
509
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000510 __ lea(edi, Operand(eax, 1));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000511 __ shl(edi, kPointerSizeLog2 + 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000512 __ add(edi, Immediate(kPointerSize * (kEntriesPerBucket - 1) * 2));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000513 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 __ j(not_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000515 __ add(edi, Immediate(kPointerSize));
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000516 __ cmp(ecx, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 __ j(not_equal, &slow);
518
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000519 // Get field offset.
ager@chromium.org5c838252010-02-19 08:53:10 +0000520 // edx : receiver
521 // ebx : receiver's map
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000522 // ecx : key
523 // eax : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 ExternalReference cache_field_offsets =
525 ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000526
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000527 // Hit on nth entry.
528 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
529 __ bind(&hit_on_nth_entry[i]);
530 if (i != 0) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000531 __ add(eax, Immediate(i));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000532 }
533 __ mov(edi,
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000534 Operand::StaticArray(eax, times_pointer_size, cache_field_offsets));
535 __ movzx_b(eax, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
536 __ sub(edi, eax);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000537 __ j(above_equal, &property_array_property);
538 if (i != 0) {
539 __ jmp(&load_in_object_property);
540 }
541 }
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542
543 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000544 __ bind(&load_in_object_property);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000545 __ movzx_b(eax, FieldOperand(ebx, Map::kInstanceSizeOffset));
546 __ add(eax, edi);
547 __ mov(eax, FieldOperand(edx, eax, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000548 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000549 __ ret(0);
550
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000551 // Load property array property.
552 __ bind(&property_array_property);
553 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
554 __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
555 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000556 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000557 __ ret(0);
558
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000559 // Do a quick inline probe of the receiver's dictionary, if it
560 // exists.
561 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000562
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000563 __ mov(eax, FieldOperand(edx, JSObject::kMapOffset));
564 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
565 GenerateGlobalInstanceTypeCheck(masm, eax, &slow);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000566
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000567 GenerateDictionaryLoad(masm, &slow, ebx, ecx, eax, edi, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000568 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 __ ret(0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000571 __ bind(&index_string);
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000572 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000573 // Now jump to the place where smi keys are handled.
574 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575}
576
577
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000578void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
579 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000580 // -- ecx : key (index)
ager@chromium.org5c838252010-02-19 08:53:10 +0000581 // -- edx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000582 // -- esp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000583 // -----------------------------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000584 Label miss;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000585
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000586 Register receiver = edx;
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000587 Register index = ecx;
588 Register scratch = ebx;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000589 Register result = eax;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000590
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000591 StringCharAtGenerator char_at_generator(receiver,
592 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +0000593 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000594 result,
595 &miss, // When not a string.
596 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000597 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000598 STRING_INDEX_IS_ARRAY_INDEX);
599 char_at_generator.GenerateFast(masm);
600 __ ret(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000601
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000602 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000603 char_at_generator.GenerateSlow(masm, call_helper);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000604
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000605 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000606 GenerateMiss(masm, MISS);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000607}
608
609
ager@chromium.org5c838252010-02-19 08:53:10 +0000610void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
611 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000612 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +0000613 // -- edx : receiver
614 // -- esp[0] : return address
615 // -----------------------------------
616 Label slow;
617
618 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000619 __ JumpIfSmi(edx, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000620
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000621 // Check that the key is an array index, that is Uint32.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000622 __ test(ecx, Immediate(kSmiTagMask | kSmiSignMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000623 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000624
625 // Get the map of the receiver.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000626 __ mov(eax, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +0000627
628 // Check that it has indexed interceptor and access checks
629 // are not enabled for this object.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000630 __ movzx_b(eax, FieldOperand(eax, Map::kBitFieldOffset));
631 __ and_(eax, Immediate(kSlowCaseBitFieldMask));
632 __ cmp(eax, Immediate(1 << Map::kHasIndexedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000633 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000634
635 // Everything is fine, call runtime.
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000636 __ pop(eax);
ager@chromium.org5c838252010-02-19 08:53:10 +0000637 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000638 __ push(ecx); // key
639 __ push(eax); // return address
ager@chromium.org5c838252010-02-19 08:53:10 +0000640
641 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 ExternalReference ref =
643 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
644 masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000645 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000646
647 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000648 GenerateMiss(masm, MISS);
ager@chromium.org3811b432009-10-28 14:53:37 +0000649}
650
651
whesse@chromium.org7b260152011-06-20 15:33:18 +0000652void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
653 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000654 // -- ecx : key
whesse@chromium.org7b260152011-06-20 15:33:18 +0000655 // -- edx : receiver
656 // -- esp[0] : return address
657 // -----------------------------------
658 Label slow, notin;
659 Factory* factory = masm->isolate()->factory();
660 Operand mapped_location =
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000661 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000662 __ mov(eax, mapped_location);
663 __ Ret();
664 __ bind(&notin);
665 // The unmapped lookup expects that the parameter map is in ebx.
666 Operand unmapped_location =
danno@chromium.org1044a4d2012-04-30 12:34:39 +0000667 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000668 __ cmp(unmapped_location, factory->the_hole_value());
669 __ j(equal, &slow);
670 __ mov(eax, unmapped_location);
671 __ Ret();
672 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000673 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000674}
675
676
677void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
678 // ----------- S t a t e -------------
679 // -- eax : value
680 // -- ecx : key
681 // -- edx : receiver
682 // -- esp[0] : return address
683 // -----------------------------------
684 Label slow, notin;
685 Operand mapped_location =
686 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, &notin, &slow);
687 __ mov(mapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000688 __ lea(ecx, mapped_location);
689 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000690 __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000691 __ Ret();
692 __ bind(&notin);
693 // The unmapped lookup expects that the parameter map is in ebx.
694 Operand unmapped_location =
695 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
696 __ mov(unmapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000697 __ lea(edi, unmapped_location);
698 __ mov(edx, eax);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000699 __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000700 __ Ret();
701 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000702 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000703}
704
705
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000706static void KeyedStoreGenerateGenericHelper(
707 MacroAssembler* masm,
708 Label* fast_object,
709 Label* fast_double,
710 Label* slow,
711 KeyedStoreCheckMap check_map,
712 KeyedStoreIncrementLength increment_length) {
713 Label transition_smi_elements;
714 Label finish_object_store, non_double_value, transition_double_elements;
715 Label fast_double_without_map_check;
716 // eax: value
717 // ecx: key (a smi)
718 // edx: receiver
719 // ebx: FixedArray receiver->elements
720 // edi: receiver map
721 // Fast case: Do the store, could either Object or double.
722 __ bind(fast_object);
723 if (check_map == kCheckMap) {
724 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
725 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
726 __ j(not_equal, fast_double);
727 }
728 // Smi stores don't require further checks.
729 Label non_smi_value;
730 __ JumpIfNotSmi(eax, &non_smi_value);
731 if (increment_length == kIncrementLength) {
732 // Add 1 to receiver->length.
733 __ add(FieldOperand(edx, JSArray::kLengthOffset),
734 Immediate(Smi::FromInt(1)));
735 }
736 // It's irrelevant whether array is smi-only or not when writing a smi.
737 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
738 __ ret(0);
739
740 __ bind(&non_smi_value);
741 // Escape to elements kind transition case.
742 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
743 __ CheckFastObjectElements(edi, &transition_smi_elements);
744
745 // Fast elements array, store the value to the elements backing store.
746 __ bind(&finish_object_store);
747 if (increment_length == kIncrementLength) {
748 // Add 1 to receiver->length.
749 __ add(FieldOperand(edx, JSArray::kLengthOffset),
750 Immediate(Smi::FromInt(1)));
751 }
752 __ mov(CodeGenerator::FixedArrayElementOperand(ebx, ecx), eax);
753 // Update write barrier for the elements array address.
754 __ mov(edx, eax); // Preserve the value which is returned.
755 __ RecordWriteArray(
756 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
757 __ ret(0);
758
759 __ bind(fast_double);
760 if (check_map == kCheckMap) {
761 // Check for fast double array case. If this fails, call through to the
762 // runtime.
763 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
764 __ j(not_equal, slow);
765 // If the value is a number, store it as a double in the FastDoubleElements
766 // array.
767 }
768 __ bind(&fast_double_without_map_check);
769 __ StoreNumberToDoubleElements(eax, ebx, ecx, edi, xmm0,
770 &transition_double_elements, false);
771 if (increment_length == kIncrementLength) {
772 // Add 1 to receiver->length.
773 __ add(FieldOperand(edx, JSArray::kLengthOffset),
774 Immediate(Smi::FromInt(1)));
775 }
776 __ ret(0);
777
778 __ bind(&transition_smi_elements);
779 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
780
781 // Transition the array appropriately depending on the value type.
782 __ CheckMap(eax,
783 masm->isolate()->factory()->heap_number_map(),
784 &non_double_value,
785 DONT_DO_SMI_CHECK);
786
787 // Value is a double. Transition FAST_SMI_ELEMENTS -> FAST_DOUBLE_ELEMENTS
788 // and complete the store.
789 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
790 FAST_DOUBLE_ELEMENTS,
791 ebx,
792 edi,
793 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000794 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
795 FAST_DOUBLE_ELEMENTS);
796 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000797 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
798 __ jmp(&fast_double_without_map_check);
799
800 __ bind(&non_double_value);
801 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
802 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
803 FAST_ELEMENTS,
804 ebx,
805 edi,
806 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000807 mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
808 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
809 slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000810 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
811 __ jmp(&finish_object_store);
812
813 __ bind(&transition_double_elements);
814 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
815 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
816 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
817 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
818 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
819 FAST_ELEMENTS,
820 ebx,
821 edi,
822 slow);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +0000823 mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
824 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000825 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
826 __ jmp(&finish_object_store);
827}
828
829
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000830void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
831 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 // ----------- S t a t e -------------
833 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000834 // -- ecx : key
835 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000836 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837 // -----------------------------------
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000838 Label slow, fast_object, fast_object_grow;
839 Label fast_double, fast_double_grow;
840 Label array, extra, check_if_double_array;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000841
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000843 __ JumpIfSmi(edx, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000844 // Get the map from the receiver.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000845 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000846 // Check that the receiver does not require access checks. We need
847 // to do this because this generic stub does not perform map checks.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000848 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
849 1 << Map::kIsAccessCheckNeeded);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000850 __ j(not_zero, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000851 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000852 __ JumpIfNotSmi(ecx, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000853 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000855 // Check that the object is some kind of JSObject.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000856 __ CmpInstanceType(edi, FIRST_JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000857 __ j(below, &slow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 // Object case: Check key against length in the elements array.
860 // eax: value
861 // edx: JSObject
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000862 // ecx: key (a smi)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000863 // edi: receiver map
864 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
865 // Check array bounds. Both the key and the length of FixedArray are smis.
866 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000867 __ j(below, &fast_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868
ager@chromium.org3811b432009-10-28 14:53:37 +0000869 // Slow case: call runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 __ bind(&slow);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000871 GenerateRuntimeSetProperty(masm, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 // Extra capacity case: Check if there is extra capacity to
874 // perform the store and update the length. Used for adding one
875 // element to the array by writing to array[array.length].
876 __ bind(&extra);
877 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000878 // edx: receiver, a JSArray
879 // ecx: key, a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000880 // ebx: receiver->elements, a FixedArray
881 // edi: receiver map
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000882 // flags: compare (ecx, edx.length())
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000883 // do not leave holes in the array:
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000884 __ j(not_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000885 __ cmp(ecx, FieldOperand(ebx, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000886 __ j(above_equal, &slow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000887 __ mov(edi, FieldOperand(ebx, HeapObject::kMapOffset));
888 __ cmp(edi, masm->isolate()->factory()->fixed_array_map());
889 __ j(not_equal, &check_if_double_array);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000890 __ jmp(&fast_object_grow);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000891
892 __ bind(&check_if_double_array);
893 __ cmp(edi, masm->isolate()->factory()->fixed_double_array_map());
894 __ j(not_equal, &slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000895 __ jmp(&fast_double_grow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000898 // array. Check that the array is in fast mode (and writable); if it
899 // is the length is always a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 __ bind(&array);
901 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000902 // edx: receiver, a JSArray
903 // ecx: key, a smi.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000904 // edi: receiver map
905 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000907 // Check the key against the length in the array and fall through to the
908 // common store code.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000909 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000910 __ j(above_equal, &extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000912 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
913 &slow, kCheckMap, kDontIncrementLength);
914 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
915 &slow, kDontCheckMap, kIncrementLength);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916}
917
918
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000919// The generated code does not accept smi keys.
920// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000921void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
922 int argc,
923 Code::Kind kind,
924 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000926 // -- ecx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000927 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000929 Label number, non_number, non_string, boolean, probe, miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930
931 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000932 Code::Flags flags = Code::ComputeFlags(kind,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000933 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000934 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000935 Code::NORMAL,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000936 argc);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000937 Isolate* isolate = masm->isolate();
938 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000939
940 // If the stub cache probing failed, the receiver might be a value.
941 // For value objects, we use the map of the prototype objects for
942 // the corresponding JSValue for the cache and that is what we need
943 // to probe.
944 //
945 // Check for number.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000946 __ JumpIfSmi(edx, &number);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000947 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000948 __ j(not_equal, &non_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000949 __ bind(&number);
950 StubCompiler::GenerateLoadGlobalFunctionPrototype(
951 masm, Context::NUMBER_FUNCTION_INDEX, edx);
952 __ jmp(&probe);
953
954 // Check for string.
955 __ bind(&non_number);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000956 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000957 __ j(above_equal, &non_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958 StubCompiler::GenerateLoadGlobalFunctionPrototype(
959 masm, Context::STRING_FUNCTION_INDEX, edx);
960 __ jmp(&probe);
961
962 // Check for boolean.
963 __ bind(&non_string);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000964 __ cmp(edx, isolate->factory()->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000965 __ j(equal, &boolean);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000966 __ cmp(edx, isolate->factory()->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000967 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000968 __ bind(&boolean);
969 StubCompiler::GenerateLoadGlobalFunctionPrototype(
970 masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
971
972 // Probe the stub cache for the value object.
973 __ bind(&probe);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000974 isolate->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx, no_reg);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000975 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000976}
977
978
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000979static void GenerateFunctionTailCall(MacroAssembler* masm,
980 int argc,
981 Label* miss) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000982 // ----------- S t a t e -------------
983 // -- ecx : name
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000984 // -- edi : function
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000985 // -- esp[0] : return address
986 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
987 // -- ...
988 // -- esp[(argc + 1) * 4] : receiver
989 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000990
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000991 // Check that the result is not a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000992 __ JumpIfSmi(edi, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000993
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000994 // Check that the value is a JavaScript function, fetching its map into eax.
995 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000996 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000997
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000998 // Invoke the function.
999 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001000 __ InvokeFunction(edi, actual, JUMP_FUNCTION,
1001 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001002}
1003
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001004
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001005// The generated code falls through if the call should be handled by runtime.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001006void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001008 // -- ecx : name
1009 // -- esp[0] : return address
1010 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1011 // -- ...
1012 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001014 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015
1016 // Get the receiver of the function from the stack; 1 ~ return address.
1017 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001019 GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001021 // eax: elements
1022 // Search the dictionary placing the result in edi.
1023 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
1024 GenerateFunctionTailCall(masm, argc, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001025
1026 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027}
1028
1029
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001030void CallICBase::GenerateMiss(MacroAssembler* masm,
1031 int argc,
1032 IC::UtilityId id,
1033 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001035 // -- ecx : name
1036 // -- esp[0] : return address
1037 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1038 // -- ...
1039 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040 // -----------------------------------
1041
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001042 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001043 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001044 __ IncrementCounter(counters->call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001045 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001046 __ IncrementCounter(counters->keyed_call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001047 }
1048
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 // Get the receiver of the function from the stack; 1 ~ return address.
1050 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001052 {
1053 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001055 // Push the receiver and the name of the function.
1056 __ push(edx);
1057 __ push(ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001059 // Call the entry.
1060 CEntryStub stub(1);
1061 __ mov(eax, Immediate(2));
1062 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
1063 __ CallStub(&stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001064
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001065 // Move result to edi and exit the internal frame.
1066 __ mov(edi, eax);
1067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001069 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001070 // This can happen only for regular CallIC but not KeyedCallIC.
1071 if (id == IC::kCallIC_Miss) {
1072 Label invoke, global;
1073 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
whesse@chromium.org7b260152011-06-20 15:33:18 +00001074 __ JumpIfSmi(edx, &invoke, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001075 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
1076 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
1077 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001078 __ j(equal, &global, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001079 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001080 __ j(not_equal, &invoke, Label::kNear);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001081
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001082 // Patch the receiver on the stack.
1083 __ bind(&global);
1084 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
1085 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
1086 __ bind(&invoke);
1087 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001090 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +00001091 ? CALL_AS_FUNCTION
1092 : CALL_AS_METHOD;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001094 __ InvokeFunction(edi,
1095 actual,
1096 JUMP_FUNCTION,
1097 NullCallWrapper(),
1098 call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
danno@chromium.org40cb8782011-05-25 07:58:50 +00001102void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1103 int argc,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001104 Code::ExtraICState extra_state) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001105 // ----------- S t a t e -------------
1106 // -- ecx : name
1107 // -- esp[0] : return address
1108 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1109 // -- ...
1110 // -- esp[(argc + 1) * 4] : receiver
1111 // -----------------------------------
1112
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001113 // Get the receiver of the function from the stack; 1 ~ return address.
1114 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001115 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC,
1116 extra_state);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001117
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001118 GenerateMiss(masm, argc, extra_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001119}
1120
1121
1122void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1123 // ----------- S t a t e -------------
1124 // -- ecx : name
1125 // -- esp[0] : return address
1126 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1127 // -- ...
1128 // -- esp[(argc + 1) * 4] : receiver
1129 // -----------------------------------
1130
1131 // Get the receiver of the function from the stack; 1 ~ return address.
1132 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1133
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001134 Label do_call, slow_call, slow_load, slow_reload_receiver;
1135 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1136 Label index_smi, index_string;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001137
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001138 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001139 __ JumpIfNotSmi(ecx, &check_string);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001140
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001141 __ bind(&index_smi);
1142 // Now the key is known to be a smi. This place is also jumped to from
1143 // where a numeric string is converted to a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001144
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001145 GenerateKeyedLoadReceiverCheck(
1146 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001147
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001148 GenerateFastArrayLoad(
1149 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001150 Isolate* isolate = masm->isolate();
1151 Counters* counters = isolate->counters();
1152 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001153
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001154 __ bind(&do_call);
1155 // receiver in edx is not used after this point.
1156 // ecx: key
1157 // edi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001158 GenerateFunctionTailCall(masm, argc, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001159
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001160 __ bind(&check_number_dictionary);
1161 // eax: elements
1162 // ecx: smi key
1163 // Check whether the elements is a number dictionary.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001164 __ CheckMap(eax,
1165 isolate->factory()->hash_table_map(),
1166 &slow_load,
1167 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001168 __ mov(ebx, ecx);
1169 __ SmiUntag(ebx);
1170 // ebx: untagged index
1171 // Receiver in edx will be clobbered, need to reload it on miss.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001172 __ LoadFromNumberDictionary(
1173 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001174 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001175 __ jmp(&do_call);
1176
1177 __ bind(&slow_reload_receiver);
1178 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1179
1180 __ bind(&slow_load);
1181 // This branch is taken when calling KeyedCallIC_Miss is neither required
1182 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001183 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001184
1185 {
1186 FrameScope scope(masm, StackFrame::INTERNAL);
1187 __ push(ecx); // save the key
1188 __ push(edx); // pass the receiver
1189 __ push(ecx); // pass the key
1190 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1191 __ pop(ecx); // restore the key
1192 // Leave the internal frame.
1193 }
1194
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001195 __ mov(edi, eax);
1196 __ jmp(&do_call);
1197
1198 __ bind(&check_string);
1199 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
1200
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001201 // The key is known to be an internalized string.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001202 // If the receiver is a regular JS object with slow properties then do
1203 // a quick inline probe of the receiver's dictionary.
1204 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001205 GenerateKeyedLoadReceiverCheck(
1206 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001207
1208 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001209 __ CheckMap(ebx,
1210 isolate->factory()->hash_table_map(),
1211 &lookup_monomorphic_cache,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001212 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001213
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001214 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001215 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001216 __ jmp(&do_call);
1217
1218 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001219 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001220 CallICBase::GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC,
1221 Code::kNoExtraICState);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001222 // Fall through on miss.
1223
1224 __ bind(&slow_call);
1225 // This branch is taken if:
1226 // - the receiver requires boxing or access check,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001227 // - the key is neither smi nor an internalized string,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001228 // - the value loaded is not a function,
1229 // - there is hope that the runtime will create a monomorphic call stub
1230 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001231 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001232 GenerateMiss(masm, argc);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001233
1234 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001235 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001236 // Now jump to the place where smi keys are handled.
1237 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001238}
1239
1240
whesse@chromium.org7b260152011-06-20 15:33:18 +00001241void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1242 int argc) {
1243 // ----------- S t a t e -------------
1244 // -- ecx : name
1245 // -- esp[0] : return address
1246 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1247 // -- ...
1248 // -- esp[(argc + 1) * 4] : receiver
1249 // -----------------------------------
1250 Label slow, notin;
1251 Factory* factory = masm->isolate()->factory();
1252 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1253 Operand mapped_location =
1254 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
1255 __ mov(edi, mapped_location);
1256 GenerateFunctionTailCall(masm, argc, &slow);
1257 __ bind(&notin);
1258 // The unmapped lookup expects that the parameter map is in ebx.
1259 Operand unmapped_location =
1260 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
1261 __ cmp(unmapped_location, factory->the_hole_value());
1262 __ j(equal, &slow);
1263 __ mov(edi, unmapped_location);
1264 GenerateFunctionTailCall(masm, argc, &slow);
1265 __ bind(&slow);
1266 GenerateMiss(masm, argc);
1267}
1268
1269
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001270void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001271 // ----------- S t a t e -------------
1272 // -- ecx : name
1273 // -- esp[0] : return address
1274 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1275 // -- ...
1276 // -- esp[(argc + 1) * 4] : receiver
1277 // -----------------------------------
1278
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001279 // Check if the name is a string.
1280 Label miss;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001281 __ JumpIfSmi(ecx, &miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001282 Condition cond = masm->IsObjectStringType(ecx, eax, eax);
1283 __ j(NegateCondition(cond), &miss);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001284 CallICBase::GenerateNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001285 __ bind(&miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001286 GenerateMiss(masm, argc);
1287}
1288
1289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1291 // ----------- S t a t e -------------
1292 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001293 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 // -----------------------------------
1296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 // Probe the stub cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001298 Code::Flags flags = Code::ComputeFlags(
1299 Code::LOAD_IC, MONOMORPHIC, Code::HANDLER_FRAGMENT);
1300 Isolate::Current()->stub_cache()->GenerateProbe(
1301 masm, flags, edx, ecx, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
1303 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +00001304 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305}
1306
1307
1308void LoadIC::GenerateNormal(MacroAssembler* masm) {
1309 // ----------- S t a t e -------------
1310 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001311 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001314 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001316 GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001318 // eax: elements
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319 // Search the dictionary placing the result in eax.
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001320 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 __ ret(0);
1322
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001323 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001325 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326}
1327
1328
1329void LoadIC::GenerateMiss(MacroAssembler* masm) {
1330 // ----------- S t a t e -------------
1331 // -- ecx : name
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001332 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 // -----------------------------------
1335
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001336 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 __ pop(ebx);
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001339 __ push(edx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001340 __ push(ecx); // name
1341 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342
mads.s.ager31e71382008-08-13 09:32:07 +00001343 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001344 ExternalReference ref =
1345 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001346 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347}
1348
1349
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001350void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001352 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00001353 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001354 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 // -----------------------------------
1356
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001357 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001358
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 __ pop(ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001360 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001361 __ push(ecx); // name
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001362 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363
mads.s.ager31e71382008-08-13 09:32:07 +00001364 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001365 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001366 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1367 masm->isolate())
1368 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001369 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001370}
1371
1372
1373void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1374 // ----------- S t a t e -------------
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001375 // -- ecx : key
ager@chromium.org5c838252010-02-19 08:53:10 +00001376 // -- edx : receiver
1377 // -- esp[0] : return address
1378 // -----------------------------------
1379
1380 __ pop(ebx);
1381 __ push(edx); // receiver
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001382 __ push(ecx); // name
ager@chromium.org5c838252010-02-19 08:53:10 +00001383 __ push(ebx); // return address
1384
1385 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001386 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387}
1388
1389
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001390void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001391 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 // ----------- S t a t e -------------
1393 // -- eax : value
1394 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001395 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397 // -----------------------------------
1398
lrn@chromium.org34e60782011-09-15 07:25:40 +00001399 Code::Flags flags =
1400 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
1402 no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403
1404 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001405 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
1408
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001409void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 // ----------- S t a t e -------------
1411 // -- eax : value
1412 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001413 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 // -----------------------------------
1416
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 __ pop(ebx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001418 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 __ push(ecx);
1420 __ push(eax);
1421 __ push(ebx);
1422
mads.s.ager31e71382008-08-13 09:32:07 +00001423 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 ExternalReference ref =
1425 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001426 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427}
1428
1429
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001430void StoreIC::GenerateNormal(MacroAssembler* masm) {
1431 // ----------- S t a t e -------------
1432 // -- eax : value
1433 // -- ecx : name
1434 // -- edx : receiver
1435 // -- esp[0] : return address
1436 // -----------------------------------
1437
1438 Label miss, restore_miss;
1439
1440 GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
1441
1442 // A lot of registers are needed for storing to slow case
1443 // objects. Push and restore receiver but rely on
1444 // GenerateDictionaryStore preserving the value and name.
1445 __ push(edx);
1446 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1447 __ Drop(1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001448 Counters* counters = masm->isolate()->counters();
1449 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001450 __ ret(0);
1451
1452 __ bind(&restore_miss);
1453 __ pop(edx);
1454
1455 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001456 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001457 GenerateMiss(masm);
1458}
1459
1460
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001461void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1462 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001463 // ----------- S t a t e -------------
1464 // -- eax : value
1465 // -- ecx : name
1466 // -- edx : receiver
1467 // -- esp[0] : return address
1468 // -----------------------------------
1469 __ pop(ebx);
1470 __ push(edx);
1471 __ push(ecx);
1472 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001473 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1474 __ push(Immediate(Smi::FromInt(strict_mode)));
1475 __ push(ebx); // return address
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001476
1477 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001479}
1480
1481
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001482void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1483 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 // ----------- S t a t e -------------
1485 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001486 // -- ecx : key
1487 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001488 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 // -----------------------------------
1490
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001491 __ pop(ebx);
1492 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001493 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001494 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001495 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1496 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode.
1497 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498
1499 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001500 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501}
1502
1503
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001504void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001505 // ----------- S t a t e -------------
1506 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001507 // -- ecx : key
1508 // -- edx : receiver
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001509 // -- esp[0] : return address
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001510 // -----------------------------------
1511
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001512 __ pop(ebx);
1513 __ push(edx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001514 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001515 __ push(eax);
1516 __ push(ebx);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001517
1518 // Do tail-call to runtime routine.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001519 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001520 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1521 masm->isolate())
1522 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1523 __ TailCallExternalReference(ref, 3, 1);
1524}
1525
1526
1527void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1528 // ----------- S t a t e -------------
1529 // -- eax : value
1530 // -- ecx : key
1531 // -- edx : receiver
1532 // -- esp[0] : return address
1533 // -----------------------------------
1534
1535 __ pop(ebx);
1536 __ push(edx);
1537 __ push(ecx);
1538 __ push(eax);
1539 __ push(ebx); // return address
1540
1541 // Do tail-call to runtime routine.
1542 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001543 __ TailCallExternalReference(ref, 3, 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001544}
1545
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001546
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001547void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1548 // ----------- S t a t e -------------
1549 // -- ebx : target map
1550 // -- edx : receiver
1551 // -- esp[0] : return address
1552 // -----------------------------------
1553 // Must return the modified receiver in eax.
1554 if (!FLAG_trace_elements_transitions) {
1555 Label fail;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001556 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1557 FAST_DOUBLE_ELEMENTS);
1558 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001559 __ mov(eax, edx);
1560 __ Ret();
1561 __ bind(&fail);
1562 }
1563
1564 __ pop(ebx);
1565 __ push(edx);
1566 __ push(ebx); // return address
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001567 // Leaving the code managed by the register allocator and return to the
1568 // convention of using esi as context register.
1569 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001570 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1571}
1572
1573
1574void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1575 MacroAssembler* masm) {
1576 // ----------- S t a t e -------------
1577 // -- ebx : target map
1578 // -- edx : receiver
1579 // -- esp[0] : return address
1580 // -----------------------------------
1581 // Must return the modified receiver in eax.
1582 if (!FLAG_trace_elements_transitions) {
1583 Label fail;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001584 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
1585 FAST_ELEMENTS);
1586 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001587 __ mov(eax, edx);
1588 __ Ret();
1589 __ bind(&fail);
1590 }
1591
1592 __ pop(ebx);
1593 __ push(edx);
1594 __ push(ebx); // return address
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001595 // Leaving the code managed by the register allocator and return to the
1596 // convention of using esi as context register.
1597 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001598 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1599}
1600
1601
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602#undef __
1603
1604
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001605Condition CompareIC::ComputeCondition(Token::Value op) {
1606 switch (op) {
1607 case Token::EQ_STRICT:
1608 case Token::EQ:
1609 return equal;
1610 case Token::LT:
1611 return less;
1612 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001613 return greater;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001614 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001615 return less_equal;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001616 case Token::GTE:
1617 return greater_equal;
1618 default:
1619 UNREACHABLE();
1620 return no_condition;
1621 }
1622}
1623
1624
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001625bool CompareIC::HasInlinedSmiCode(Address address) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001626 // The address of the instruction following the call.
1627 Address test_instruction_address =
1628 address + Assembler::kCallTargetAddressOffset;
1629
1630 // If the instruction following the call is not a test al, nothing
1631 // was inlined.
1632 return *test_instruction_address == Assembler::kTestAlByte;
1633}
1634
1635
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001636void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001637 // The address of the instruction following the call.
1638 Address test_instruction_address =
1639 address + Assembler::kCallTargetAddressOffset;
1640
1641 // If the instruction following the call is not a test al, nothing
1642 // was inlined.
1643 if (*test_instruction_address != Assembler::kTestAlByte) {
1644 ASSERT(*test_instruction_address == Assembler::kNopByte);
1645 return;
1646 }
1647
1648 Address delta_address = test_instruction_address + 1;
1649 // The delta to the start of the map check instruction and the
1650 // condition code uses at the patched jump.
1651 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1652 if (FLAG_trace_ic) {
1653 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1654 address, test_instruction_address, delta);
1655 }
1656
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001657 // Patch with a short conditional jump. Enabling means switching from a short
1658 // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling is the
1659 // reverse operation of that.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001660 Address jmp_address = test_instruction_address - delta;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001661 ASSERT((check == ENABLE_INLINED_SMI_CHECK)
1662 ? (*jmp_address == Assembler::kJncShortOpcode ||
1663 *jmp_address == Assembler::kJcShortOpcode)
1664 : (*jmp_address == Assembler::kJnzShortOpcode ||
1665 *jmp_address == Assembler::kJzShortOpcode));
1666 Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
1667 ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
1668 : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001669 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001670}
1671
1672
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001674
1675#endif // V8_TARGET_ARCH_IA32