blob: 7d3ead2eac1e037967b0a6be323621f38103d9c0 [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 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
103// name is not a symbol, and will jump to the miss_label in that
104// 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),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147 Immediate(PropertyDetails::TypeField::mask() << 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
160// call if name is not a symbol, and will jump to the miss_label in
161// 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;
201 const int kTypeAndReadOnlyMask
202 = (PropertyDetails::TypeField::mask() |
203 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
204 __ 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);
215 __ RecordWrite(elements, r0, r1);
216}
217
218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
220 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000221 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 // -- ecx : name
223 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000225 Label miss;
226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000227 StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
228 __ bind(&miss);
229 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
230}
231
232
ager@chromium.org378b34e2011-01-28 08:04:38 +0000233void LoadIC::GenerateStringLength(MacroAssembler* masm,
234 bool support_wrappers) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000236 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 // -- ecx : name
238 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240 Label miss;
241
ager@chromium.org378b34e2011-01-28 08:04:38 +0000242 StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss,
243 support_wrappers);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000244 __ bind(&miss);
245 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
246}
247
248
249void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
250 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000251 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000252 // -- ecx : name
253 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255 Label miss;
256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
258 __ bind(&miss);
259 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
260}
261
262
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000263// Checks the receiver for special cases (value type, slow case bits).
264// Falls through for regular JS object.
265static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
266 Register receiver,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000267 Register map,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000268 int interceptor_bit,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000269 Label* slow) {
270 // Register use:
271 // receiver - holds the receiver and is unchanged.
272 // Scratch registers:
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000273 // map - used to hold the map of the receiver.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000274
275 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000276 __ JumpIfSmi(receiver, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000277
278 // Get the map of the receiver.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000279 __ mov(map, FieldOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000280
281 // Check bit field.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000282 __ test_b(FieldOperand(map, Map::kBitFieldOffset),
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000283 (1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000284 __ j(not_zero, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000285 // Check that the object is some kind of JS object EXCEPT JS Value type.
286 // In the case that the object is a value-wrapper object,
287 // we enter the runtime system to make sure that indexing
288 // into string objects works as intended.
289 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
290
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000291 __ CmpInstanceType(map, JS_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000292 __ j(below, slow);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000293}
294
295
296// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000297// If not_fast_array is NULL, doesn't perform the elements map check.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000298static void GenerateFastArrayLoad(MacroAssembler* masm,
299 Register receiver,
300 Register key,
301 Register scratch,
302 Register result,
303 Label* not_fast_array,
304 Label* out_of_range) {
305 // Register use:
306 // receiver - holds the receiver and is unchanged.
307 // key - holds the key and is unchanged (must be a smi).
308 // Scratch registers:
309 // scratch - used to hold elements of the receiver and the loaded value.
310 // result - holds the result on exit if the load succeeds and
311 // we fall through.
312
313 __ mov(scratch, FieldOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000314 if (not_fast_array != NULL) {
315 // Check that the object is in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000316 __ CheckMap(scratch,
317 FACTORY->fixed_array_map(),
318 not_fast_array,
319 DONT_DO_SMI_CHECK);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000320 } else {
321 __ AssertFastElements(scratch);
322 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000323 // Check that the key (index) is within bounds.
324 __ cmp(key, FieldOperand(scratch, FixedArray::kLengthOffset));
325 __ j(above_equal, out_of_range);
326 // Fast case: Do the load.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000327 STATIC_ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000328 __ mov(scratch, FieldOperand(scratch, key, times_2, FixedArray::kHeaderSize));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 __ cmp(Operand(scratch), Immediate(FACTORY->the_hole_value()));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000330 // In case the loaded value is the_hole we have to consult GetProperty
331 // to ensure the prototype chain is searched.
332 __ j(equal, out_of_range);
333 if (!result.is(scratch)) {
334 __ mov(result, scratch);
335 }
336}
337
338
339// Checks whether a key is an array index string or a symbol string.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000340// Falls through if the key is a symbol.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000341static void GenerateKeyStringCheck(MacroAssembler* masm,
342 Register key,
343 Register map,
344 Register hash,
345 Label* index_string,
346 Label* not_symbol) {
347 // Register use:
348 // key - holds the key and is unchanged. Assumed to be non-smi.
349 // Scratch registers:
350 // map - used to hold the map of the key.
351 // hash - used to hold the hash of the key.
352 __ CmpObjectType(key, FIRST_NONSTRING_TYPE, map);
353 __ j(above_equal, not_symbol);
354
355 // Is the string an array index, with cached numeric value?
356 __ mov(hash, FieldOperand(key, String::kHashFieldOffset));
357 __ test(hash, Immediate(String::kContainsCachedArrayIndexMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000358 __ j(zero, index_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000359
360 // Is the string a symbol?
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000361 STATIC_ASSERT(kSymbolTag != 0);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000362 __ test_b(FieldOperand(map, Map::kInstanceTypeOffset), kIsSymbolMask);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000363 __ j(zero, not_symbol);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000364}
365
366
whesse@chromium.org7b260152011-06-20 15:33:18 +0000367static Operand GenerateMappedArgumentsLookup(MacroAssembler* masm,
368 Register object,
369 Register key,
370 Register scratch1,
371 Register scratch2,
372 Label* unmapped_case,
373 Label* slow_case) {
374 Heap* heap = masm->isolate()->heap();
375 Factory* factory = masm->isolate()->factory();
376
ager@chromium.org04921a82011-06-27 13:21:41 +0000377 // Check that the receiver is a JSObject. Because of the elements
378 // map check later, we do not need to check for interceptors or
379 // whether it requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000380 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +0000381 // Check that the object is some kind of JSObject.
382 __ CmpObjectType(object, FIRST_JS_RECEIVER_TYPE, scratch1);
383 __ j(below, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000384
385 // Check that the key is a positive smi.
386 __ test(key, Immediate(0x8000001));
387 __ j(not_zero, slow_case);
388
389 // Load the elements into scratch1 and check its map.
390 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
391 __ mov(scratch1, FieldOperand(object, JSObject::kElementsOffset));
392 __ CheckMap(scratch1, arguments_map, slow_case, DONT_DO_SMI_CHECK);
393
394 // Check if element is in the range of mapped arguments. If not, jump
395 // to the unmapped lookup with the parameter map in scratch1.
396 __ mov(scratch2, FieldOperand(scratch1, FixedArray::kLengthOffset));
397 __ sub(Operand(scratch2), Immediate(Smi::FromInt(2)));
398 __ cmp(key, Operand(scratch2));
399 __ j(greater_equal, unmapped_case);
400
401 // Load element index and check whether it is the hole.
402 const int kHeaderSize = FixedArray::kHeaderSize + 2 * kPointerSize;
403 __ mov(scratch2, FieldOperand(scratch1,
404 key,
405 times_half_pointer_size,
406 kHeaderSize));
407 __ cmp(scratch2, factory->the_hole_value());
408 __ j(equal, unmapped_case);
409
410 // Load value from context and return it. We can reuse scratch1 because
411 // we do not jump to the unmapped lookup (which requires the parameter
412 // map in scratch1).
413 const int kContextOffset = FixedArray::kHeaderSize;
414 __ mov(scratch1, FieldOperand(scratch1, kContextOffset));
415 return FieldOperand(scratch1,
416 scratch2,
417 times_half_pointer_size,
418 Context::kHeaderSize);
419}
420
421
422static Operand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
423 Register key,
424 Register parameter_map,
425 Register scratch,
426 Label* slow_case) {
427 // Element is in arguments backing store, which is referenced by the
428 // second element of the parameter_map.
429 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
430 Register backing_store = parameter_map;
431 __ mov(backing_store, FieldOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000432 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
433 __ CheckMap(backing_store, fixed_array_map, slow_case, DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000434 __ mov(scratch, FieldOperand(backing_store, FixedArray::kLengthOffset));
435 __ cmp(key, Operand(scratch));
436 __ j(greater_equal, slow_case);
437 return FieldOperand(backing_store,
438 key,
439 times_half_pointer_size,
440 FixedArray::kHeaderSize);
441}
442
443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000444void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
445 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000446 // -- eax : key
447 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000448 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 // -----------------------------------
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000450 Label slow, check_string, index_smi, index_string, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000451 Label probe_dictionary, check_number_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000454 __ JumpIfNotSmi(eax, &check_string);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000455 __ bind(&index_smi);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000456 // Now the key is known to be a smi. This place is also jumped to from
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000457 // where a numeric string is converted to a smi.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000458
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000459 GenerateKeyedLoadReceiverCheck(
460 masm, edx, ecx, Map::kHasIndexedInterceptor, &slow);
461
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000462 // Check the receiver's map to see if it has fast elements.
463 __ CheckFastElements(ecx, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000464
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000465 GenerateFastArrayLoad(masm,
466 edx,
467 eax,
468 ecx,
469 eax,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000470 NULL,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000471 &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000472 Isolate* isolate = masm->isolate();
473 Counters* counters = isolate->counters();
474 __ IncrementCounter(counters->keyed_load_generic_smi(), 1);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000475 __ ret(0);
476
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000477 __ bind(&check_number_dictionary);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000478 __ mov(ebx, eax);
479 __ SmiUntag(ebx);
480 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset));
481
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000482 // Check whether the elements is a number dictionary.
483 // edx: receiver
484 // ebx: untagged index
485 // eax: key
486 // ecx: elements
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000487 __ CheckMap(ecx,
488 isolate->factory()->hash_table_map(),
489 &slow,
490 DONT_DO_SMI_CHECK);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000491 Label slow_pop_receiver;
492 // Push receiver on the stack to free up a register for the dictionary
493 // probing.
494 __ push(edx);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000495 __ LoadFromNumberDictionary(&slow_pop_receiver,
496 ecx,
497 eax,
498 ebx,
499 edx,
500 edi,
501 eax);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000502 // Pop receiver before returning.
503 __ pop(edx);
504 __ ret(0);
505
506 __ bind(&slow_pop_receiver);
507 // Pop the receiver from the stack and jump to runtime.
508 __ pop(edx);
509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 __ bind(&slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000511 // Slow case: jump to runtime.
512 // edx: receiver
513 // eax: key
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000514 __ IncrementCounter(counters->keyed_load_generic_slow(), 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000515 GenerateRuntimeGetProperty(masm);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000516
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517 __ bind(&check_string);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000518 GenerateKeyStringCheck(masm, eax, ecx, ebx, &index_string, &slow);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000519
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000520 GenerateKeyedLoadReceiverCheck(
521 masm, edx, ecx, Map::kHasNamedInterceptor, &slow);
522
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000523 // If the receiver is a fast-case object, check the keyed lookup
ager@chromium.org5c838252010-02-19 08:53:10 +0000524 // cache. Otherwise probe the dictionary.
525 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000526 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000527 Immediate(isolate->factory()->hash_table_map()));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000528 __ j(equal, &probe_dictionary);
529
530 // Load the map of the receiver, compute the keyed lookup cache hash
531 // based on 32 bits of the map pointer and the string hash.
ager@chromium.org5c838252010-02-19 08:53:10 +0000532 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
533 __ mov(ecx, ebx);
534 __ shr(ecx, KeyedLookupCache::kMapHashShift);
535 __ mov(edi, FieldOperand(eax, String::kHashFieldOffset));
536 __ shr(edi, String::kHashShift);
537 __ xor_(ecx, Operand(edi));
538 __ and_(ecx, KeyedLookupCache::kCapacityMask);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000539
540 // Load the key (consisting of map and symbol) from the cache and
541 // check for match.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 ExternalReference cache_keys =
543 ExternalReference::keyed_lookup_cache_keys(masm->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000544 __ mov(edi, ecx);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000545 __ shl(edi, kPointerSizeLog2 + 1);
546 __ cmp(ebx, Operand::StaticArray(edi, times_1, cache_keys));
547 __ j(not_equal, &slow);
548 __ add(Operand(edi), Immediate(kPointerSize));
ager@chromium.org5c838252010-02-19 08:53:10 +0000549 __ cmp(eax, Operand::StaticArray(edi, times_1, cache_keys));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 __ j(not_equal, &slow);
551
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000552 // Get field offset.
ager@chromium.org5c838252010-02-19 08:53:10 +0000553 // edx : receiver
554 // ebx : receiver's map
555 // eax : key
556 // ecx : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000557 ExternalReference cache_field_offsets =
558 ExternalReference::keyed_lookup_cache_field_offsets(masm->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +0000559 __ mov(edi,
560 Operand::StaticArray(ecx, times_pointer_size, cache_field_offsets));
561 __ movzx_b(ecx, FieldOperand(ebx, Map::kInObjectPropertiesOffset));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000562 __ sub(edi, Operand(ecx));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000563 __ j(above_equal, &property_array_property);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000564
565 // Load in-object property.
ager@chromium.org5c838252010-02-19 08:53:10 +0000566 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceSizeOffset));
567 __ add(ecx, Operand(edi));
568 __ mov(eax, FieldOperand(edx, ecx, times_pointer_size, 0));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000569 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570 __ ret(0);
571
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000572 // Load property array property.
573 __ bind(&property_array_property);
574 __ mov(eax, FieldOperand(edx, JSObject::kPropertiesOffset));
575 __ mov(eax, FieldOperand(eax, edi, times_pointer_size,
576 FixedArray::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000577 __ IncrementCounter(counters->keyed_load_generic_lookup_cache(), 1);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000578 __ ret(0);
579
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580 // Do a quick inline probe of the receiver's dictionary, if it
581 // exists.
582 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000583
584 __ mov(ecx, FieldOperand(edx, JSObject::kMapOffset));
585 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
586 GenerateGlobalInstanceTypeCheck(masm, ecx, &slow);
587
588 GenerateDictionaryLoad(masm, &slow, ebx, eax, ecx, edi, eax);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000589 __ IncrementCounter(counters->keyed_load_generic_symbol(), 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000590 __ ret(0);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000592 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000593 __ IndexFromHash(ebx, eax);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000594 // Now jump to the place where smi keys are handled.
595 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596}
597
598
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000599void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
600 // ----------- S t a t e -------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000601 // -- eax : key (index)
ager@chromium.org5c838252010-02-19 08:53:10 +0000602 // -- edx : receiver
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000603 // -- esp[0] : return address
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000604 // -----------------------------------
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000605 Label miss;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000606
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000607 Register receiver = edx;
608 Register index = eax;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000609 Register scratch1 = ebx;
610 Register scratch2 = ecx;
611 Register result = eax;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000612
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000613 StringCharAtGenerator char_at_generator(receiver,
614 index,
615 scratch1,
616 scratch2,
617 result,
618 &miss, // When not a string.
619 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000620 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000621 STRING_INDEX_IS_ARRAY_INDEX);
622 char_at_generator.GenerateFast(masm);
623 __ ret(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000624
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000625 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000626 char_at_generator.GenerateSlow(masm, call_helper);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000627
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000628 __ bind(&miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000629 GenerateMiss(masm, false);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000630}
631
632
ager@chromium.org5c838252010-02-19 08:53:10 +0000633void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
634 // ----------- S t a t e -------------
635 // -- eax : key
636 // -- edx : receiver
637 // -- esp[0] : return address
638 // -----------------------------------
639 Label slow;
640
641 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000642 __ JumpIfSmi(edx, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000643
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000644 // Check that the key is an array index, that is Uint32.
645 __ test(eax, Immediate(kSmiTagMask | kSmiSignMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000646 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000647
648 // Get the map of the receiver.
649 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
650
651 // Check that it has indexed interceptor and access checks
652 // are not enabled for this object.
653 __ movzx_b(ecx, FieldOperand(ecx, Map::kBitFieldOffset));
654 __ and_(Operand(ecx), Immediate(kSlowCaseBitFieldMask));
655 __ cmp(Operand(ecx), Immediate(1 << Map::kHasIndexedInterceptor));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000656 __ j(not_zero, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +0000657
658 // Everything is fine, call runtime.
659 __ pop(ecx);
660 __ push(edx); // receiver
661 __ push(eax); // key
662 __ push(ecx); // return address
663
664 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000665 ExternalReference ref =
666 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
667 masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000668 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000669
670 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000671 GenerateMiss(masm, false);
ager@chromium.org3811b432009-10-28 14:53:37 +0000672}
673
674
whesse@chromium.org7b260152011-06-20 15:33:18 +0000675void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
676 // ----------- S t a t e -------------
677 // -- eax : key
678 // -- edx : receiver
679 // -- esp[0] : return address
680 // -----------------------------------
681 Label slow, notin;
682 Factory* factory = masm->isolate()->factory();
683 Operand mapped_location =
684 GenerateMappedArgumentsLookup(masm, edx, eax, ebx, ecx, &notin, &slow);
685 __ mov(eax, mapped_location);
686 __ Ret();
687 __ bind(&notin);
688 // The unmapped lookup expects that the parameter map is in ebx.
689 Operand unmapped_location =
690 GenerateUnmappedArgumentsLookup(masm, eax, ebx, ecx, &slow);
691 __ cmp(unmapped_location, factory->the_hole_value());
692 __ j(equal, &slow);
693 __ mov(eax, unmapped_location);
694 __ Ret();
695 __ bind(&slow);
696 GenerateMiss(masm, false);
697}
698
699
700void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
701 // ----------- S t a t e -------------
702 // -- eax : value
703 // -- ecx : key
704 // -- edx : receiver
705 // -- esp[0] : return address
706 // -----------------------------------
707 Label slow, notin;
708 Operand mapped_location =
709 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, edi, &notin, &slow);
710 __ mov(mapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000711 __ lea(ecx, mapped_location);
712 __ mov(edx, eax);
713 __ RecordWrite(ebx, ecx, edx);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000714 __ Ret();
715 __ bind(&notin);
716 // The unmapped lookup expects that the parameter map is in ebx.
717 Operand unmapped_location =
718 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, edi, &slow);
719 __ mov(unmapped_location, eax);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000720 __ lea(edi, unmapped_location);
721 __ mov(edx, eax);
722 __ RecordWrite(ebx, edi, edx);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000723 __ Ret();
724 __ bind(&slow);
725 GenerateMiss(masm, false);
726}
727
728
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000729void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
730 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731 // ----------- S t a t e -------------
732 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000733 // -- ecx : key
734 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736 // -----------------------------------
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000737 Label slow, fast, array, extra;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000740 __ JumpIfSmi(edx, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000741 // Get the map from the receiver.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000742 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000743 // Check that the receiver does not require access checks. We need
744 // to do this because this generic stub does not perform map checks.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000745 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
746 1 << Map::kIsAccessCheckNeeded);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000747 __ j(not_zero, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000748 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000749 __ JumpIfNotSmi(ecx, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000750 __ CmpInstanceType(edi, JS_ARRAY_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 __ j(equal, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000752 // Check that the object is some kind of JSObject.
753 __ CmpInstanceType(edi, FIRST_JS_RECEIVER_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000754 __ j(below, &slow);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000755 __ CmpInstanceType(edi, JS_PROXY_TYPE);
756 __ j(equal, &slow);
757 __ CmpInstanceType(edi, JS_FUNCTION_PROXY_TYPE);
758 __ j(equal, &slow);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 // Object case: Check key against length in the elements array.
761 // eax: value
762 // edx: JSObject
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000763 // ecx: key (a smi)
764 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000765 // Check that the object is in fast mode and writable.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000766 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000767 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000768 __ j(below, &fast);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769
ager@chromium.org3811b432009-10-28 14:53:37 +0000770 // Slow case: call runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771 __ bind(&slow);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000772 GenerateRuntimeSetProperty(masm, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774 // Extra capacity case: Check if there is extra capacity to
775 // perform the store and update the length. Used for adding one
776 // element to the array by writing to array[array.length].
777 __ bind(&extra);
778 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000779 // edx: receiver, a JSArray
780 // ecx: key, a smi.
781 // edi: receiver->elements, a FixedArray
782 // flags: compare (ecx, edx.length())
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000783 // do not leave holes in the array:
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000784 __ j(not_equal, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000785 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000786 __ j(above_equal, &slow);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000787 // Add 1 to receiver->length, and go to fast array write.
788 __ add(FieldOperand(edx, JSArray::kLengthOffset),
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000789 Immediate(Smi::FromInt(1)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790 __ jmp(&fast);
791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000792 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000793 // array. Check that the array is in fast mode (and writable); if it
794 // is the length is always a smi.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795 __ bind(&array);
796 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000797 // edx: receiver, a JSArray
798 // ecx: key, a smi.
799 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000800 __ CheckMap(edi, FACTORY->fixed_array_map(), &slow, DONT_DO_SMI_CHECK);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801
802 // Check the key against the length in the array, compute the
803 // address to store into and fall through to fast case.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000804 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000805 __ j(above_equal, &extra);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000807 // Fast case: Do the store.
808 __ bind(&fast);
809 // eax: value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000810 // ecx: key (a smi)
811 // edx: receiver
812 // edi: FixedArray receiver->elements
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000813 __ mov(CodeGenerator::FixedArrayElementOperand(edi, ecx), eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814 // Update write barrier for the elements array address.
815 __ mov(edx, Operand(eax));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000816 __ RecordWrite(edi, 0, edx, ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817 __ ret(0);
818}
819
820
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000821// The generated code does not accept smi keys.
822// The generated code falls through if both probes miss.
823static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
824 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000825 Code::Kind kind,
826 Code::ExtraICState extra_ic_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000828 // -- ecx : name
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000829 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830 // -----------------------------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000831 Label number, non_number, non_string, boolean, probe, miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832
833 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000834 Code::Flags flags = Code::ComputeFlags(kind,
835 NOT_IN_LOOP,
836 MONOMORPHIC,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000837 extra_ic_state,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000838 NORMAL,
839 argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
841 eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
843 // If the stub cache probing failed, the receiver might be a value.
844 // For value objects, we use the map of the prototype objects for
845 // the corresponding JSValue for the cache and that is what we need
846 // to probe.
847 //
848 // Check for number.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000849 __ JumpIfSmi(edx, &number);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000850 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ebx);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000851 __ j(not_equal, &non_number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 __ bind(&number);
853 StubCompiler::GenerateLoadGlobalFunctionPrototype(
854 masm, Context::NUMBER_FUNCTION_INDEX, edx);
855 __ jmp(&probe);
856
857 // Check for string.
858 __ bind(&non_number);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000859 __ CmpInstanceType(ebx, FIRST_NONSTRING_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000860 __ j(above_equal, &non_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861 StubCompiler::GenerateLoadGlobalFunctionPrototype(
862 masm, Context::STRING_FUNCTION_INDEX, edx);
863 __ jmp(&probe);
864
865 // Check for boolean.
866 __ bind(&non_string);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000867 __ cmp(edx, FACTORY->true_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000868 __ j(equal, &boolean);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000869 __ cmp(edx, FACTORY->false_value());
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000870 __ j(not_equal, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 __ bind(&boolean);
872 StubCompiler::GenerateLoadGlobalFunctionPrototype(
873 masm, Context::BOOLEAN_FUNCTION_INDEX, edx);
874
875 // Probe the stub cache for the value object.
876 __ bind(&probe);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000877 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
878 no_reg);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000879 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880}
881
882
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000883static void GenerateFunctionTailCall(MacroAssembler* masm,
884 int argc,
885 Label* miss) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000886 // ----------- S t a t e -------------
887 // -- ecx : name
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000888 // -- edi : function
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000889 // -- esp[0] : return address
890 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
891 // -- ...
892 // -- esp[(argc + 1) * 4] : receiver
893 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000894
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000895 // Check that the result is not a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000896 __ JumpIfSmi(edi, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000897
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000898 // Check that the value is a JavaScript function, fetching its map into eax.
899 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000900 __ j(not_equal, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000901
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000902 // Invoke the function.
903 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000904 __ InvokeFunction(edi, actual, JUMP_FUNCTION,
905 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000906}
907
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000908// The generated code falls through if the call should be handled by runtime.
909static void GenerateCallNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000911 // -- ecx : name
912 // -- esp[0] : return address
913 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
914 // -- ...
915 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000917 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000918
919 // Get the receiver of the function from the stack; 1 ~ return address.
920 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000922 GenerateStringDictionaryReceiverCheck(masm, edx, eax, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000923
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000924 // eax: elements
925 // Search the dictionary placing the result in edi.
926 GenerateDictionaryLoad(masm, &miss, eax, ecx, edi, ebx, edi);
927 GenerateFunctionTailCall(masm, argc, &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000928
929 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930}
931
932
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000933static void GenerateCallMiss(MacroAssembler* masm,
934 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000935 IC::UtilityId id,
936 Code::ExtraICState extra_ic_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000937 // ----------- S t a t e -------------
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000938 // -- ecx : name
939 // -- esp[0] : return address
940 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
941 // -- ...
942 // -- esp[(argc + 1) * 4] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943 // -----------------------------------
944
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000945 Counters* counters = masm->isolate()->counters();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000946 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000947 __ IncrementCounter(counters->call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000948 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000949 __ IncrementCounter(counters->keyed_call_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000950 }
951
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952 // Get the receiver of the function from the stack; 1 ~ return address.
953 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000954
955 // Enter an internal frame.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000956 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957
958 // Push the receiver and the name of the function.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000959 __ push(edx);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000960 __ push(ecx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961
962 // Call the entry.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000963 CEntryStub stub(1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000964 __ mov(eax, Immediate(2));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 __ mov(ebx, Immediate(ExternalReference(IC_Utility(id), masm->isolate())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966 __ CallStub(&stub);
967
968 // Move result to edi and exit the internal frame.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000969 __ mov(edi, eax);
ager@chromium.org236ad962008-09-25 09:45:57 +0000970 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000971
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000972 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000973 // This can happen only for regular CallIC but not KeyedCallIC.
974 if (id == IC::kCallIC_Miss) {
975 Label invoke, global;
976 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // receiver
whesse@chromium.org7b260152011-06-20 15:33:18 +0000977 __ JumpIfSmi(edx, &invoke, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000978 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset));
979 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
980 __ cmp(ebx, JS_GLOBAL_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000981 __ j(equal, &global, Label::kNear);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000982 __ cmp(ebx, JS_BUILTINS_OBJECT_TYPE);
karlklose@chromium.org83a47282011-05-11 11:54:09 +0000983 __ j(not_equal, &invoke, Label::kNear);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000984
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000985 // Patch the receiver on the stack.
986 __ bind(&global);
987 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
988 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
989 __ bind(&invoke);
990 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 // Invoke the function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000993 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
994 ? CALL_AS_FUNCTION
995 : CALL_AS_METHOD;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000997 __ InvokeFunction(edi,
998 actual,
999 JUMP_FUNCTION,
1000 NullCallWrapper(),
1001 call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002}
1003
1004
danno@chromium.org40cb8782011-05-25 07:58:50 +00001005void CallIC::GenerateMegamorphic(MacroAssembler* masm,
1006 int argc,
1007 Code::ExtraICState extra_ic_state) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001008 // ----------- S t a t e -------------
1009 // -- ecx : name
1010 // -- esp[0] : return address
1011 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1012 // -- ...
1013 // -- esp[(argc + 1) * 4] : receiver
1014 // -----------------------------------
1015
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001016 // Get the receiver of the function from the stack; 1 ~ return address.
1017 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +00001018 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
1019
1020 GenerateMiss(masm, argc, extra_ic_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001021}
1022
1023
1024void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001025 // ----------- S t a t e -------------
1026 // -- ecx : name
1027 // -- esp[0] : return address
1028 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1029 // -- ...
1030 // -- esp[(argc + 1) * 4] : receiver
1031 // -----------------------------------
1032
1033 GenerateCallNormal(masm, argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001034 GenerateMiss(masm, argc, Code::kNoExtraICState);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001035}
1036
1037
danno@chromium.org40cb8782011-05-25 07:58:50 +00001038void CallIC::GenerateMiss(MacroAssembler* masm,
1039 int argc,
1040 Code::ExtraICState extra_ic_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001041 // ----------- S t a t e -------------
1042 // -- ecx : name
1043 // -- esp[0] : return address
1044 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1045 // -- ...
1046 // -- esp[(argc + 1) * 4] : receiver
1047 // -----------------------------------
1048
danno@chromium.org40cb8782011-05-25 07:58:50 +00001049 GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001050}
1051
1052
1053void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
1054 // ----------- S t a t e -------------
1055 // -- ecx : name
1056 // -- esp[0] : return address
1057 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1058 // -- ...
1059 // -- esp[(argc + 1) * 4] : receiver
1060 // -----------------------------------
1061
1062 // Get the receiver of the function from the stack; 1 ~ return address.
1063 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1064
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001065 Label do_call, slow_call, slow_load, slow_reload_receiver;
1066 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
1067 Label index_smi, index_string;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001068
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001069 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001070 __ JumpIfNotSmi(ecx, &check_string);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001071
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001072 __ bind(&index_smi);
1073 // Now the key is known to be a smi. This place is also jumped to from
1074 // where a numeric string is converted to a smi.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001075
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001076 GenerateKeyedLoadReceiverCheck(
1077 masm, edx, eax, Map::kHasIndexedInterceptor, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001078
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001079 GenerateFastArrayLoad(
1080 masm, edx, ecx, eax, edi, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001081 Isolate* isolate = masm->isolate();
1082 Counters* counters = isolate->counters();
1083 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001084
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001085 __ bind(&do_call);
1086 // receiver in edx is not used after this point.
1087 // ecx: key
1088 // edi: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001089 GenerateFunctionTailCall(masm, argc, &slow_call);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001090
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001091 __ bind(&check_number_dictionary);
1092 // eax: elements
1093 // ecx: smi key
1094 // Check whether the elements is a number dictionary.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001095 __ CheckMap(eax,
1096 isolate->factory()->hash_table_map(),
1097 &slow_load,
1098 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001099 __ mov(ebx, ecx);
1100 __ SmiUntag(ebx);
1101 // ebx: untagged index
1102 // Receiver in edx will be clobbered, need to reload it on miss.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001103 __ LoadFromNumberDictionary(
1104 &slow_reload_receiver, eax, ecx, ebx, edx, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001105 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001106 __ jmp(&do_call);
1107
1108 __ bind(&slow_reload_receiver);
1109 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1110
1111 __ bind(&slow_load);
1112 // This branch is taken when calling KeyedCallIC_Miss is neither required
1113 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001114 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001115 __ EnterInternalFrame();
1116 __ push(ecx); // save the key
1117 __ push(edx); // pass the receiver
1118 __ push(ecx); // pass the key
1119 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
1120 __ pop(ecx); // restore the key
1121 __ LeaveInternalFrame();
1122 __ mov(edi, eax);
1123 __ jmp(&do_call);
1124
1125 __ bind(&check_string);
1126 GenerateKeyStringCheck(masm, ecx, eax, ebx, &index_string, &slow_call);
1127
1128 // The key is known to be a symbol.
1129 // If the receiver is a regular JS object with slow properties then do
1130 // a quick inline probe of the receiver's dictionary.
1131 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001132 GenerateKeyedLoadReceiverCheck(
1133 masm, edx, eax, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001134
1135 __ mov(ebx, FieldOperand(edx, JSObject::kPropertiesOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001136 __ CheckMap(ebx,
1137 isolate->factory()->hash_table_map(),
1138 &lookup_monomorphic_cache,
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00001139 DONT_DO_SMI_CHECK);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001140
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001141 GenerateDictionaryLoad(masm, &slow_load, ebx, ecx, eax, edi, edi);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001142 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001143 __ jmp(&do_call);
1144
1145 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001146 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001147 GenerateMonomorphicCacheProbe(masm,
1148 argc,
1149 Code::KEYED_CALL_IC,
1150 Code::kNoExtraICState);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001151 // Fall through on miss.
1152
1153 __ bind(&slow_call);
1154 // This branch is taken if:
1155 // - the receiver requires boxing or access check,
1156 // - the key is neither smi nor symbol,
1157 // - the value loaded is not a function,
1158 // - there is hope that the runtime will create a monomorphic call stub
1159 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001160 __ IncrementCounter(counters->keyed_call_generic_slow(), 1);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001161 GenerateMiss(masm, argc);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001162
1163 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001164 __ IndexFromHash(ebx, ecx);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001165 // Now jump to the place where smi keys are handled.
1166 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001167}
1168
1169
whesse@chromium.org7b260152011-06-20 15:33:18 +00001170void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1171 int argc) {
1172 // ----------- S t a t e -------------
1173 // -- ecx : name
1174 // -- esp[0] : return address
1175 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1176 // -- ...
1177 // -- esp[(argc + 1) * 4] : receiver
1178 // -----------------------------------
1179 Label slow, notin;
1180 Factory* factory = masm->isolate()->factory();
1181 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
1182 Operand mapped_location =
1183 GenerateMappedArgumentsLookup(masm, edx, ecx, ebx, eax, &notin, &slow);
1184 __ mov(edi, mapped_location);
1185 GenerateFunctionTailCall(masm, argc, &slow);
1186 __ bind(&notin);
1187 // The unmapped lookup expects that the parameter map is in ebx.
1188 Operand unmapped_location =
1189 GenerateUnmappedArgumentsLookup(masm, ecx, ebx, eax, &slow);
1190 __ cmp(unmapped_location, factory->the_hole_value());
1191 __ j(equal, &slow);
1192 __ mov(edi, unmapped_location);
1193 GenerateFunctionTailCall(masm, argc, &slow);
1194 __ bind(&slow);
1195 GenerateMiss(masm, argc);
1196}
1197
1198
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001199void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001200 // ----------- S t a t e -------------
1201 // -- ecx : name
1202 // -- esp[0] : return address
1203 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1204 // -- ...
1205 // -- esp[(argc + 1) * 4] : receiver
1206 // -----------------------------------
1207
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001208 // Check if the name is a string.
1209 Label miss;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001210 __ JumpIfSmi(ecx, &miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001211 Condition cond = masm->IsObjectStringType(ecx, eax, eax);
1212 __ j(NegateCondition(cond), &miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001213 GenerateCallNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001214 __ bind(&miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001215 GenerateMiss(masm, argc);
1216}
1217
1218
1219void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001220 // ----------- S t a t e -------------
1221 // -- ecx : name
1222 // -- esp[0] : return address
1223 // -- esp[(argc - n) * 4] : arg[n] (zero-based)
1224 // -- ...
1225 // -- esp[(argc + 1) * 4] : receiver
1226 // -----------------------------------
1227
danno@chromium.org40cb8782011-05-25 07:58:50 +00001228 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001229}
1230
1231
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
1233 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001234 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235 // -- ecx : name
1236 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 // -----------------------------------
1238
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001240 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
1241 NOT_IN_LOOP,
1242 MONOMORPHIC);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, eax, ecx, ebx,
1244 edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245
1246 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +00001247 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248}
1249
1250
1251void LoadIC::GenerateNormal(MacroAssembler* masm) {
1252 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001253 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001254 // -- ecx : name
1255 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001257 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001259 GenerateStringDictionaryReceiverCheck(masm, eax, edx, ebx, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001261 // edx: elements
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 // Search the dictionary placing the result in eax.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001263 GenerateDictionaryLoad(masm, &miss, edx, ecx, edi, ebx, eax);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264 __ ret(0);
1265
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001266 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001268 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001269}
1270
1271
1272void LoadIC::GenerateMiss(MacroAssembler* masm) {
1273 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001274 // -- eax : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 // -- ecx : name
1276 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 // -----------------------------------
1278
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001279 __ IncrementCounter(masm->isolate()->counters()->load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 __ pop(ebx);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001282 __ push(eax); // receiver
1283 __ push(ecx); // name
1284 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285
mads.s.ager31e71382008-08-13 09:32:07 +00001286 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001287 ExternalReference ref =
1288 ExternalReference(IC_Utility(kLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001289 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290}
1291
1292
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001293void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +00001295 // -- eax : key
1296 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 // -----------------------------------
1299
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001300 __ IncrementCounter(masm->isolate()->counters()->keyed_load_miss(), 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302 __ pop(ebx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001303 __ push(edx); // receiver
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001304 __ push(eax); // name
1305 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306
mads.s.ager31e71382008-08-13 09:32:07 +00001307 // Perform tail call to the entry.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001308 ExternalReference ref = force_generic
1309 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric),
1310 masm->isolate())
1311 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001312 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001313}
1314
1315
1316void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1317 // ----------- S t a t e -------------
1318 // -- eax : key
1319 // -- edx : receiver
1320 // -- esp[0] : return address
1321 // -----------------------------------
1322
1323 __ pop(ebx);
1324 __ push(edx); // receiver
1325 __ push(eax); // name
1326 __ push(ebx); // return address
1327
1328 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001329 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330}
1331
1332
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001333void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001334 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 // ----------- S t a t e -------------
1336 // -- eax : value
1337 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001342 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1343 NOT_IN_LOOP,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001344 MONOMORPHIC,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001345 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
1347 no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348
1349 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001350 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351}
1352
1353
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001354void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 // ----------- S t a t e -------------
1356 // -- eax : value
1357 // -- ecx : name
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001358 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 // -----------------------------------
1361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 __ pop(ebx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001363 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 __ push(ecx);
1365 __ push(eax);
1366 __ push(ebx);
1367
mads.s.ager31e71382008-08-13 09:32:07 +00001368 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001369 ExternalReference ref =
1370 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001371 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372}
1373
1374
ager@chromium.org5c838252010-02-19 08:53:10 +00001375void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1376 // ----------- S t a t e -------------
1377 // -- eax : value
1378 // -- ecx : name
1379 // -- edx : receiver
1380 // -- esp[0] : return address
1381 // -----------------------------------
1382 //
1383 // This accepts as a receiver anything JSObject::SetElementsLength accepts
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001384 // (currently anything except for external arrays which means anything with
1385 // elements of FixedArray type.), but currently is restricted to JSArray.
ager@chromium.org5c838252010-02-19 08:53:10 +00001386 // Value must be a number, but only smis are accepted as the most common case.
1387
1388 Label miss;
1389
1390 Register receiver = edx;
1391 Register value = eax;
1392 Register scratch = ebx;
1393
1394 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001395 __ JumpIfSmi(receiver, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001396
1397 // Check that the object is a JS array.
1398 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001399 __ j(not_equal, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001400
1401 // Check that elements are FixedArray.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001402 // We rely on StoreIC_ArrayLength below to deal with all types of
1403 // fast elements (including COW).
ager@chromium.org5c838252010-02-19 08:53:10 +00001404 __ mov(scratch, FieldOperand(receiver, JSArray::kElementsOffset));
1405 __ CmpObjectType(scratch, FIXED_ARRAY_TYPE, scratch);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001406 __ j(not_equal, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001407
1408 // Check that value is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001409 __ JumpIfNotSmi(value, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001410
1411 // Prepare tail call to StoreIC_ArrayLength.
1412 __ pop(scratch);
1413 __ push(receiver);
1414 __ push(value);
1415 __ push(scratch); // return address
1416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001417 ExternalReference ref =
1418 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001419 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001420
1421 __ bind(&miss);
1422
1423 GenerateMiss(masm);
1424}
1425
1426
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001427void StoreIC::GenerateNormal(MacroAssembler* masm) {
1428 // ----------- S t a t e -------------
1429 // -- eax : value
1430 // -- ecx : name
1431 // -- edx : receiver
1432 // -- esp[0] : return address
1433 // -----------------------------------
1434
1435 Label miss, restore_miss;
1436
1437 GenerateStringDictionaryReceiverCheck(masm, edx, ebx, edi, &miss);
1438
1439 // A lot of registers are needed for storing to slow case
1440 // objects. Push and restore receiver but rely on
1441 // GenerateDictionaryStore preserving the value and name.
1442 __ push(edx);
1443 GenerateDictionaryStore(masm, &restore_miss, ebx, ecx, eax, edx, edi);
1444 __ Drop(1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001445 Counters* counters = masm->isolate()->counters();
1446 __ IncrementCounter(counters->store_normal_hit(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001447 __ ret(0);
1448
1449 __ bind(&restore_miss);
1450 __ pop(edx);
1451
1452 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001453 __ IncrementCounter(counters->store_normal_miss(), 1);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001454 GenerateMiss(masm);
1455}
1456
1457
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001458void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1459 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001460 // ----------- S t a t e -------------
1461 // -- eax : value
1462 // -- ecx : name
1463 // -- edx : receiver
1464 // -- esp[0] : return address
1465 // -----------------------------------
1466 __ pop(ebx);
1467 __ push(edx);
1468 __ push(ecx);
1469 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001470 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1471 __ push(Immediate(Smi::FromInt(strict_mode)));
1472 __ push(ebx); // return address
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001473
1474 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001475 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001476}
1477
1478
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1480 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // ----------- S t a t e -------------
1482 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001483 // -- ecx : key
1484 // -- edx : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001485 // -- esp[0] : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001486 // -----------------------------------
1487
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001488 __ pop(ebx);
1489 __ push(edx);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001491 __ push(eax);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001492 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes
1493 __ push(Immediate(Smi::FromInt(strict_mode))); // Strict mode.
1494 __ push(ebx); // return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495
1496 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001497 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001498}
1499
1500
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001501void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001502 // ----------- S t a t e -------------
1503 // -- eax : value
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001504 // -- ecx : key
1505 // -- edx : receiver
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001506 // -- esp[0] : return address
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001507 // -----------------------------------
1508
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001509 __ pop(ebx);
1510 __ push(edx);
ager@chromium.org5c838252010-02-19 08:53:10 +00001511 __ push(ecx);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001512 __ push(eax);
1513 __ push(ebx);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001514
1515 // Do tail-call to runtime routine.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001516 ExternalReference ref = force_generic
1517 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1518 masm->isolate())
1519 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1520 __ TailCallExternalReference(ref, 3, 1);
1521}
1522
1523
1524void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1525 // ----------- S t a t e -------------
1526 // -- eax : value
1527 // -- ecx : key
1528 // -- edx : receiver
1529 // -- esp[0] : return address
1530 // -----------------------------------
1531
1532 __ pop(ebx);
1533 __ push(edx);
1534 __ push(ecx);
1535 __ push(eax);
1536 __ push(ebx); // return address
1537
1538 // Do tail-call to runtime routine.
1539 ExternalReference ref(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001540 __ TailCallExternalReference(ref, 3, 1);
kasperl@chromium.org1accd572008-10-07 10:57:21 +00001541}
1542
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001543
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544#undef __
1545
1546
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001547Condition CompareIC::ComputeCondition(Token::Value op) {
1548 switch (op) {
1549 case Token::EQ_STRICT:
1550 case Token::EQ:
1551 return equal;
1552 case Token::LT:
1553 return less;
1554 case Token::GT:
1555 // Reverse left and right operands to obtain ECMA-262 conversion order.
1556 return less;
1557 case Token::LTE:
1558 // Reverse left and right operands to obtain ECMA-262 conversion order.
1559 return greater_equal;
1560 case Token::GTE:
1561 return greater_equal;
1562 default:
1563 UNREACHABLE();
1564 return no_condition;
1565 }
1566}
1567
1568
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001569static bool HasInlinedSmiCode(Address address) {
1570 // The address of the instruction following the call.
1571 Address test_instruction_address =
1572 address + Assembler::kCallTargetAddressOffset;
1573
1574 // If the instruction following the call is not a test al, nothing
1575 // was inlined.
1576 return *test_instruction_address == Assembler::kTestAlByte;
1577}
1578
1579
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001580void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1581 HandleScope scope;
1582 Handle<Code> rewritten;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001583 State previous_state = GetState();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001584
1585 State state = TargetState(previous_state, HasInlinedSmiCode(address()), x, y);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001586 if (state == GENERIC) {
1587 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
1588 rewritten = stub.GetCode();
1589 } else {
1590 ICCompareStub stub(op_, state);
1591 rewritten = stub.GetCode();
1592 }
1593 set_target(*rewritten);
1594
1595#ifdef DEBUG
1596 if (FLAG_trace_ic) {
1597 PrintF("[CompareIC (%s->%s)#%s]\n",
1598 GetStateName(previous_state),
1599 GetStateName(state),
1600 Token::Name(op_));
1601 }
1602#endif
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001603
1604 // Activate inlined smi code.
1605 if (previous_state == UNINITIALIZED) {
1606 PatchInlinedSmiCode(address());
1607 }
1608}
1609
1610
1611void PatchInlinedSmiCode(Address address) {
1612 // The address of the instruction following the call.
1613 Address test_instruction_address =
1614 address + Assembler::kCallTargetAddressOffset;
1615
1616 // If the instruction following the call is not a test al, nothing
1617 // was inlined.
1618 if (*test_instruction_address != Assembler::kTestAlByte) {
1619 ASSERT(*test_instruction_address == Assembler::kNopByte);
1620 return;
1621 }
1622
1623 Address delta_address = test_instruction_address + 1;
1624 // The delta to the start of the map check instruction and the
1625 // condition code uses at the patched jump.
1626 int8_t delta = *reinterpret_cast<int8_t*>(delta_address);
1627 if (FLAG_trace_ic) {
1628 PrintF("[ patching ic at %p, test=%p, delta=%d\n",
1629 address, test_instruction_address, delta);
1630 }
1631
1632 // Patch with a short conditional jump. There must be a
1633 // short jump-if-carry/not-carry at this position.
1634 Address jmp_address = test_instruction_address - delta;
1635 ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
1636 *jmp_address == Assembler::kJcShortOpcode);
1637 Condition cc = *jmp_address == Assembler::kJncShortOpcode
1638 ? not_zero
1639 : zero;
1640 *jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001641}
1642
1643
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001645
1646#endif // V8_TARGET_ARCH_IA32