blob: a3b2a6e2a19842e2c59584a70029a29c675a1360 [file] [log] [blame]
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_ARM
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000032#include "assembler-arm.h"
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000033#include "code-stubs.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000034#include "codegen.h"
fschneider@chromium.org013f3e12010-04-26 13:27:52 +000035#include "disasm.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "ic-inl.h"
37#include "runtime.h"
38#include "stub-cache.h"
39
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
43
44// ----------------------------------------------------------------------------
45// Static IC stub generators.
46//
47
ager@chromium.org65dad4b2009-04-23 08:48:43 +000048#define __ ACCESS_MASM(masm)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000050
51static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
52 Register type,
53 Label* global_object) {
54 // Register usage:
55 // type: holds the receiver instance type on entry.
56 __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
57 __ b(eq, global_object);
58 __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
59 __ b(eq, global_object);
60 __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
61 __ b(eq, global_object);
62}
63
64
65// Generated code falls through if the receiver is a regular non-global
66// JS object with slow properties and no interceptors.
ulan@chromium.org750145a2013-03-07 15:14:13 +000067static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
68 Register receiver,
69 Register elements,
70 Register t0,
71 Register t1,
72 Label* miss) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000073 // Register usage:
74 // receiver: holds the receiver on entry and is unchanged.
75 // elements: holds the property dictionary on fall through.
76 // Scratch registers:
77 // t0: used to holds the receiver map.
78 // t1: used to holds the receiver instance type, receiver bit mask and
79 // elements map.
80
81 // Check that the receiver isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +000082 __ JumpIfSmi(receiver, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000083
84 // Check that the receiver is a valid JS object.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000085 __ CompareObjectType(receiver, t0, t1, FIRST_SPEC_OBJECT_TYPE);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000086 __ b(lt, miss);
87
88 // If this assert fails, we have to check upper bound too.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000089 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000090
91 GenerateGlobalInstanceTypeCheck(masm, t1, miss);
92
93 // Check that the global object does not require access checks.
94 __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
95 __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
96 (1 << Map::kHasNamedInterceptor)));
ager@chromium.org378b34e2011-01-28 08:04:38 +000097 __ b(ne, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000098
99 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
100 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
101 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
102 __ cmp(t1, ip);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000103 __ b(ne, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000104}
105
106
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000107// Helper function used from LoadIC/CallIC GenerateNormal.
108//
109// elements: Property dictionary. It is not clobbered if a jump to the miss
110// label is done.
111// name: Property name. It is not clobbered if a jump to the miss label is
112// done
113// result: Register for the result. It is only updated if a jump to the miss
114// label is not done. Can be the same as elements or name clobbering
115// one of these in the case of not jumping to the miss label.
116// The two scratch registers need to be different from elements, name and
117// result.
118// The generated code assumes that the receiver has slow properties,
119// is not a global object and does not have interceptors.
120static void GenerateDictionaryLoad(MacroAssembler* masm,
121 Label* miss,
122 Register elements,
123 Register name,
124 Register result,
125 Register scratch1,
126 Register scratch2) {
127 // Main use of the scratch registers.
128 // scratch1: Used as temporary and to hold the capacity of the property
129 // dictionary.
130 // scratch2: Used as temporary.
131 Label done;
132
133 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000134 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
135 miss,
136 &done,
137 elements,
138 name,
139 scratch1,
140 scratch2);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000141
142 // If probing finds an entry check that the value is a normal
143 // property.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000144 __ bind(&done); // scratch2 == elements + 4 * index
ulan@chromium.org750145a2013-03-07 15:14:13 +0000145 const int kElementsStartOffset = NameDictionary::kHeaderSize +
146 NameDictionary::kElementsStartIndex * kPointerSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000147 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
148 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000149 __ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000150 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151
152 // Get the value at the masked, scaled index and return.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000153 __ ldr(result,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000154 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155}
156
157
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000158// Helper function used from StoreIC::GenerateNormal.
159//
160// elements: Property dictionary. It is not clobbered if a jump to the miss
161// label is done.
162// name: Property name. It is not clobbered if a jump to the miss label is
163// done
164// value: The value to store.
165// The two scratch registers need to be different from elements, name and
166// result.
167// The generated code assumes that the receiver has slow properties,
168// is not a global object and does not have interceptors.
169static void GenerateDictionaryStore(MacroAssembler* masm,
170 Label* miss,
171 Register elements,
172 Register name,
173 Register value,
174 Register scratch1,
175 Register scratch2) {
176 // Main use of the scratch registers.
177 // scratch1: Used as temporary and to hold the capacity of the property
178 // dictionary.
179 // scratch2: Used as temporary.
180 Label done;
181
182 // Probe the dictionary.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000183 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
184 miss,
185 &done,
186 elements,
187 name,
188 scratch1,
189 scratch2);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000190
191 // If probing finds an entry in the dictionary check that the value
192 // is a normal property that is not read only.
193 __ bind(&done); // scratch2 == elements + 4 * index
ulan@chromium.org750145a2013-03-07 15:14:13 +0000194 const int kElementsStartOffset = NameDictionary::kHeaderSize +
195 NameDictionary::kElementsStartIndex * kPointerSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000196 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000197 const int kTypeAndReadOnlyMask =
198 (PropertyDetails::TypeField::kMask |
199 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000200 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
201 __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
202 __ b(ne, miss);
203
204 // Store the value at the masked, scaled index and return.
205 const int kValueOffset = kElementsStartOffset + kPointerSize;
206 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
207 __ str(value, MemOperand(scratch2));
208
209 // Update the write barrier. Make sure not to clobber the value.
210 __ mov(scratch1, value);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000211 __ RecordWrite(
212 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000213}
214
215
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000216// Checks the receiver for special cases (value type, slow case bits).
217// Falls through for regular JS object.
218static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
219 Register receiver,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000220 Register map,
221 Register scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000222 int interceptor_bit,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000223 Label* slow) {
224 // Check that the object isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000225 __ JumpIfSmi(receiver, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000226 // Get the map of the receiver.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000227 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000228 // Check bit field.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000229 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
230 __ tst(scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000231 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000232 __ b(ne, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000233 // Check that the object is some kind of JS object EXCEPT JS Value type.
234 // In the case that the object is a value-wrapper object,
235 // we enter the runtime system to make sure that indexing into string
236 // objects work as intended.
237 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000238 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
239 __ cmp(scratch, Operand(JS_OBJECT_TYPE));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000240 __ b(lt, slow);
241}
242
243
244// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000245// If not_fast_array is NULL, doesn't perform the elements map check.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000246static void GenerateFastArrayLoad(MacroAssembler* masm,
247 Register receiver,
248 Register key,
249 Register elements,
250 Register scratch1,
251 Register scratch2,
252 Register result,
253 Label* not_fast_array,
254 Label* out_of_range) {
255 // Register use:
256 //
257 // receiver - holds the receiver on entry.
258 // Unchanged unless 'result' is the same register.
259 //
260 // key - holds the smi key on entry.
261 // Unchanged unless 'result' is the same register.
262 //
263 // elements - holds the elements of the receiver on exit.
264 //
265 // result - holds the result on exit if the load succeeded.
266 // Allowed to be the the same as 'receiver' or 'key'.
267 // Unchanged on bailout so 'receiver' and 'key' can be safely
268 // used by further computation.
269 //
270 // Scratch registers:
271 //
272 // scratch1 - used to hold elements map and elements length.
273 // Holds the elements map if not_fast_array branch is taken.
274 //
275 // scratch2 - used to hold the loaded value.
276
277 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000278 if (not_fast_array != NULL) {
279 // Check that the object is in fast mode and writable.
280 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
281 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
282 __ cmp(scratch1, ip);
283 __ b(ne, not_fast_array);
284 } else {
285 __ AssertFastElements(elements);
286 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000287 // Check that the key (index) is within bounds.
288 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
289 __ cmp(key, Operand(scratch1));
290 __ b(hs, out_of_range);
291 // Fast case: Do the load.
292 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000293 __ ldr(scratch2, MemOperand::PointerAddressFromSmiKey(scratch1, key));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000294 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
295 __ cmp(scratch2, ip);
296 // In case the loaded value is the_hole we have to consult GetProperty
297 // to ensure the prototype chain is searched.
298 __ b(eq, out_of_range);
299 __ mov(result, scratch2);
300}
301
302
ulan@chromium.org750145a2013-03-07 15:14:13 +0000303// Checks whether a key is an array index string or a unique name.
304// Falls through if a key is a unique name.
305static void GenerateKeyNameCheck(MacroAssembler* masm,
306 Register key,
307 Register map,
308 Register hash,
309 Label* index_string,
310 Label* not_unique) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000311 // The key is not a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000312 Label unique;
313 // Is it a name?
314 __ CompareObjectType(key, map, hash, LAST_UNIQUE_NAME_TYPE);
315 __ b(hi, not_unique);
316 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
317 __ b(eq, &unique);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000318
319 // Is the string an array index, with cached numeric value?
ulan@chromium.org750145a2013-03-07 15:14:13 +0000320 __ ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
321 __ tst(hash, Operand(Name::kContainsCachedArrayIndexMask));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000322 __ b(eq, index_string);
323
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000324 // Is the string internalized? We know it's a string, so a single
325 // bit test is enough.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000326 // map: key map
327 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000328 STATIC_ASSERT(kInternalizedTag == 0);
329 __ tst(hash, Operand(kIsNotInternalizedMask));
330 __ b(ne, not_unique);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000331
332 __ bind(&unique);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000333}
334
335
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336// Defined in ic.cc.
337Object* CallIC_Miss(Arguments args);
338
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000339// The generated code does not accept smi keys.
340// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000341void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
342 int argc,
343 Code::Kind kind,
344 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 // ----------- S t a t e -------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000346 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000347 // -- r2 : name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 // -----------------------------------
349 Label number, non_number, non_string, boolean, probe, miss;
350
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000352 Code::Flags flags = Code::ComputeFlags(kind,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000353 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000354 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000355 Code::NORMAL,
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000356 argc);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000357 masm->isolate()->stub_cache()->GenerateProbe(
ulan@chromium.org812308e2012-02-29 15:58:45 +0000358 masm, flags, r1, r2, r3, r4, r5, r6);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359
360 // If the stub cache probing failed, the receiver might be a value.
361 // For value objects, we use the map of the prototype objects for
362 // the corresponding JSValue for the cache and that is what we need
363 // to probe.
364 //
365 // Check for number.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000366 __ JumpIfSmi(r1, &number);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000367 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 __ b(ne, &non_number);
369 __ bind(&number);
370 StubCompiler::GenerateLoadGlobalFunctionPrototype(
371 masm, Context::NUMBER_FUNCTION_INDEX, r1);
372 __ b(&probe);
373
374 // Check for string.
375 __ bind(&non_number);
376 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
377 __ b(hs, &non_string);
378 StubCompiler::GenerateLoadGlobalFunctionPrototype(
379 masm, Context::STRING_FUNCTION_INDEX, r1);
380 __ b(&probe);
381
382 // Check for boolean.
383 __ bind(&non_string);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000384 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
385 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 __ b(eq, &boolean);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000387 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
388 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 __ b(ne, &miss);
390 __ bind(&boolean);
391 StubCompiler::GenerateLoadGlobalFunctionPrototype(
392 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
393
394 // Probe the stub cache for the value object.
395 __ bind(&probe);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000396 masm->isolate()->stub_cache()->GenerateProbe(
ulan@chromium.org812308e2012-02-29 15:58:45 +0000397 masm, flags, r1, r2, r3, r4, r5, r6);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400}
401
402
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000403static void GenerateFunctionTailCall(MacroAssembler* masm,
404 int argc,
405 Label* miss,
406 Register scratch) {
407 // r1: function
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000408
409 // Check that the value isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000410 __ JumpIfSmi(r1, miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000411
412 // Check that the value is a JSFunction.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000413 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000414 __ b(ne, miss);
415
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000416 // Invoke the function.
417 ParameterCount actual(argc);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000418 __ InvokeFunction(r1, actual, JUMP_FUNCTION,
419 NullCallWrapper(), CALL_AS_METHOD);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000420}
421
422
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000423void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000424 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000425 // -- r2 : name
426 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000428 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429
mads.s.ager31e71382008-08-13 09:32:07 +0000430 // Get the receiver of the function from the stack into r1.
431 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000432
ulan@chromium.org750145a2013-03-07 15:14:13 +0000433 GenerateNameDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000434
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000435 // r0: elements
436 // Search the dictionary - put result in register r1.
437 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000438
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000439 GenerateFunctionTailCall(masm, argc, &miss, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000442}
443
444
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445void CallICBase::GenerateMiss(MacroAssembler* masm,
446 int argc,
447 IC::UtilityId id,
448 Code::ExtraICState extra_state) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000450 // -- r2 : name
451 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000452 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000453 Isolate* isolate = masm->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000454
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000455 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000456 __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000457 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000458 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000459 }
460
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000461 // Get the receiver of the function from the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +0000462 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000464 {
465 FrameScope scope(masm, StackFrame::INTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000467 // Push the receiver and the name of the function.
468 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000469
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000470 // Call the entry.
471 __ mov(r0, Operand(2));
472 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000474 CEntryStub stub(1);
475 __ CallStub(&stub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000477 // Move result to r1 and leave the internal frame.
478 __ mov(r1, Operand(r0));
479 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000480
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000481 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000482 // This can happen only for regular CallIC but not KeyedCallIC.
483 if (id == IC::kCallIC_Miss) {
484 Label invoke, global;
485 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
whesse@chromium.org7b260152011-06-20 15:33:18 +0000486 __ JumpIfSmi(r2, &invoke);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000487 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
488 __ b(eq, &global);
489 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
490 __ b(ne, &invoke);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000491
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000492 // Patch the receiver on the stack.
493 __ bind(&global);
494 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
495 __ str(r2, MemOperand(sp, argc * kPointerSize));
496 __ bind(&invoke);
497 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000499 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000500 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +0000501 ? CALL_AS_FUNCTION
502 : CALL_AS_METHOD;
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000503 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000504 __ InvokeFunction(r1,
505 actual,
506 JUMP_FUNCTION,
507 NullCallWrapper(),
508 call_kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509}
510
511
danno@chromium.org40cb8782011-05-25 07:58:50 +0000512void CallIC::GenerateMegamorphic(MacroAssembler* masm,
513 int argc,
514 Code::ExtraICState extra_ic_state) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000515 // ----------- S t a t e -------------
516 // -- r2 : name
517 // -- lr : return address
518 // -----------------------------------
519
520 // Get the receiver of the function from the stack into r1.
521 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000522 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
523 GenerateMiss(masm, argc, extra_ic_state);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000524}
525
526
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000527void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000528 // ----------- S t a t e -------------
529 // -- r2 : name
530 // -- lr : return address
531 // -----------------------------------
532
533 // Get the receiver of the function from the stack into r1.
534 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
535
536 Label do_call, slow_call, slow_load, slow_reload_receiver;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000537 Label check_number_dictionary, check_name, lookup_monomorphic_cache;
538 Label index_smi, index_name;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000539
540 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000541 __ JumpIfNotSmi(r2, &check_name);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000542 __ bind(&index_smi);
543 // Now the key is known to be a smi. This place is also jumped to from below
544 // where a numeric string is converted to a smi.
545
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000546 GenerateKeyedLoadReceiverCheck(
547 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000548
549 GenerateFastArrayLoad(
550 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000551 Counters* counters = masm->isolate()->counters();
552 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000553
554 __ bind(&do_call);
555 // receiver in r1 is not used after this point.
556 // r2: key
557 // r1: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000558 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000559
560 __ bind(&check_number_dictionary);
561 // r2: key
562 // r3: elements map
563 // r4: elements
564 // Check whether the elements is a number dictionary.
565 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
566 __ cmp(r3, ip);
567 __ b(ne, &slow_load);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000568 __ SmiUntag(r0, r2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000569 // r0: untagged index
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000570 __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000571 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000572 __ jmp(&do_call);
573
574 __ bind(&slow_load);
575 // This branch is taken when calling KeyedCallIC_Miss is neither required
576 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000577 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000578 {
579 FrameScope scope(masm, StackFrame::INTERNAL);
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000580 __ Push(r2, r1); // save the key and the receiver
581 __ push(r2); // pass the receiver and the key
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000582 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
583 __ pop(r2); // restore the key
584 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000585 __ mov(r1, r0);
586 __ jmp(&do_call);
587
ulan@chromium.org750145a2013-03-07 15:14:13 +0000588 __ bind(&check_name);
589 GenerateKeyNameCheck(masm, r2, r0, r3, &index_name, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000590
ulan@chromium.org750145a2013-03-07 15:14:13 +0000591 // The key is known to be a unique name.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000592 // If the receiver is a regular JS object with slow properties then do
593 // a quick inline probe of the receiver's dictionary.
594 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000595 GenerateKeyedLoadReceiverCheck(
596 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000597
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000598 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
599 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000600 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
601 __ cmp(r3, ip);
602 __ b(ne, &lookup_monomorphic_cache);
603
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000604 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000605 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000606 __ jmp(&do_call);
607
608 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000609 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000610 GenerateMonomorphicCacheProbe(masm,
611 argc,
612 Code::KEYED_CALL_IC,
613 Code::kNoExtraICState);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000614 // Fall through on miss.
615
616 __ bind(&slow_call);
617 // This branch is taken if:
618 // - the receiver requires boxing or access check,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000619 // - the key is neither smi nor a unique name,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000620 // - the value loaded is not a function,
621 // - there is hope that the runtime will create a monomorphic call stub
622 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000623 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000624 GenerateMiss(masm, argc);
625
ulan@chromium.org750145a2013-03-07 15:14:13 +0000626 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000627 __ IndexFromHash(r3, r2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000628 // Now jump to the place where smi keys are handled.
629 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000630}
631
632
633void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000634 // ----------- S t a t e -------------
635 // -- r2 : name
636 // -- lr : return address
637 // -----------------------------------
638
ulan@chromium.org750145a2013-03-07 15:14:13 +0000639 // Check if the name is really a name.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000640 Label miss;
whesse@chromium.org7b260152011-06-20 15:33:18 +0000641 __ JumpIfSmi(r2, &miss);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000642 __ IsObjectNameType(r2, r0, &miss);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000643
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000644 CallICBase::GenerateNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000645 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000646 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000647}
648
649
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
651 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 // -- r2 : name
653 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000654 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655 // -----------------------------------
656
657 // Probe the stub cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000658 Code::Flags flags = Code::ComputeFlags(
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +0000659 Code::HANDLER, MONOMORPHIC, Code::kNoExtraICState,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000660 Code::NORMAL, Code::LOAD_IC);
dslomov@chromium.orge97852d2013-09-12 09:02:59 +0000661 masm->isolate()->stub_cache()->GenerateProbe(
ulan@chromium.org812308e2012-02-29 15:58:45 +0000662 masm, flags, r0, r2, r3, r4, r5, r6);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663
664 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +0000665 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666}
667
668
669void LoadIC::GenerateNormal(MacroAssembler* masm) {
670 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671 // -- r2 : name
672 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000673 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000675 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000676
ulan@chromium.org750145a2013-03-07 15:14:13 +0000677 GenerateNameDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000678
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000679 // r1: elements
680 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681 __ Ret();
682
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000683 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000685 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000686}
687
688
689void LoadIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691 // -- r2 : name
692 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000693 // -- r0 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000694 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000695 Isolate* isolate = masm->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000697 __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000698
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000699 __ mov(r3, r0);
700 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000701
mads.s.ager31e71382008-08-13 09:32:07 +0000702 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000703 ExternalReference ref =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000704 ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000705 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706}
707
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000708
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000709void LoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
710 // ---------- S t a t e --------------
711 // -- r2 : name
712 // -- lr : return address
713 // -- r0 : receiver
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000714 // -----------------------------------
715
716 __ mov(r3, r0);
717 __ Push(r3, r2);
718
719 __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
720}
721
722
whesse@chromium.org7b260152011-06-20 15:33:18 +0000723static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
724 Register object,
725 Register key,
726 Register scratch1,
727 Register scratch2,
728 Register scratch3,
729 Label* unmapped_case,
730 Label* slow_case) {
731 Heap* heap = masm->isolate()->heap();
732
ager@chromium.org04921a82011-06-27 13:21:41 +0000733 // Check that the receiver is a JSObject. Because of the map check
734 // later, we do not need to check for interceptors or whether it
735 // requires access checks.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000736 __ JumpIfSmi(object, slow_case);
ager@chromium.org04921a82011-06-27 13:21:41 +0000737 // Check that the object is some kind of JSObject.
738 __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE);
739 __ b(lt, slow_case);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000740
741 // Check that the key is a positive smi.
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000742 __ tst(key, Operand(0x80000001));
whesse@chromium.org7b260152011-06-20 15:33:18 +0000743 __ b(ne, slow_case);
744
745 // Load the elements into scratch1 and check its map.
746 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
747 __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
748 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
749
750 // Check if element is in the range of mapped arguments. If not, jump
751 // to the unmapped lookup with the parameter map in scratch1.
752 __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
753 __ sub(scratch2, scratch2, Operand(Smi::FromInt(2)));
754 __ cmp(key, Operand(scratch2));
755 __ b(cs, unmapped_case);
756
757 // Load element index and check whether it is the hole.
758 const int kOffset =
759 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
760
761 __ mov(scratch3, Operand(kPointerSize >> 1));
762 __ mul(scratch3, key, scratch3);
763 __ add(scratch3, scratch3, Operand(kOffset));
764
765 __ ldr(scratch2, MemOperand(scratch1, scratch3));
766 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
767 __ cmp(scratch2, scratch3);
768 __ b(eq, unmapped_case);
769
770 // Load value from context and return it. We can reuse scratch1 because
771 // we do not jump to the unmapped lookup (which requires the parameter
772 // map in scratch1).
773 __ ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
774 __ mov(scratch3, Operand(kPointerSize >> 1));
775 __ mul(scratch3, scratch2, scratch3);
776 __ add(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
777 return MemOperand(scratch1, scratch3);
778}
779
780
781static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
782 Register key,
783 Register parameter_map,
784 Register scratch,
785 Label* slow_case) {
786 // Element is in arguments backing store, which is referenced by the
787 // second element of the parameter_map. The parameter_map register
788 // must be loaded with the parameter map of the arguments object and is
789 // overwritten.
790 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
791 Register backing_store = parameter_map;
792 __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000793 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
794 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
795 DONT_DO_SMI_CHECK);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000796 __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
797 __ cmp(key, Operand(scratch));
798 __ b(cs, slow_case);
799 __ mov(scratch, Operand(kPointerSize >> 1));
800 __ mul(scratch, key, scratch);
801 __ add(scratch,
802 scratch,
803 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
804 return MemOperand(backing_store, scratch);
805}
806
807
808void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
809 // ---------- S t a t e --------------
810 // -- lr : return address
811 // -- r0 : key
812 // -- r1 : receiver
813 // -----------------------------------
814 Label slow, notin;
815 MemOperand mapped_location =
816 GenerateMappedArgumentsLookup(masm, r1, r0, r2, r3, r4, &notin, &slow);
817 __ ldr(r0, mapped_location);
818 __ Ret();
819 __ bind(&notin);
820 // The unmapped lookup expects that the parameter map is in r2.
821 MemOperand unmapped_location =
822 GenerateUnmappedArgumentsLookup(masm, r0, r2, r3, &slow);
823 __ ldr(r2, unmapped_location);
824 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
825 __ cmp(r2, r3);
826 __ b(eq, &slow);
827 __ mov(r0, r2);
828 __ Ret();
829 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000830 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000831}
832
833
834void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
835 // ---------- S t a t e --------------
836 // -- r0 : value
837 // -- r1 : key
838 // -- r2 : receiver
839 // -- lr : return address
840 // -----------------------------------
841 Label slow, notin;
842 MemOperand mapped_location =
843 GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, &notin, &slow);
844 __ str(r0, mapped_location);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000845 __ add(r6, r3, r5);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000846 __ mov(r9, r0);
847 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000848 __ Ret();
849 __ bind(&notin);
850 // The unmapped lookup expects that the parameter map is in r3.
851 MemOperand unmapped_location =
852 GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
853 __ str(r0, unmapped_location);
fschneider@chromium.org59c14262011-06-23 10:27:56 +0000854 __ add(r6, r3, r4);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000855 __ mov(r9, r0);
856 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000857 __ Ret();
858 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000859 GenerateMiss(masm, MISS);
whesse@chromium.org7b260152011-06-20 15:33:18 +0000860}
861
862
863void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
864 int argc) {
865 // ----------- S t a t e -------------
866 // -- r2 : name
867 // -- lr : return address
868 // -----------------------------------
869 Label slow, notin;
870 // Load receiver.
871 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
872 MemOperand mapped_location =
873 GenerateMappedArgumentsLookup(masm, r1, r2, r3, r4, r5, &notin, &slow);
874 __ ldr(r1, mapped_location);
875 GenerateFunctionTailCall(masm, argc, &slow, r3);
876 __ bind(&notin);
877 // The unmapped lookup expects that the parameter map is in r3.
878 MemOperand unmapped_location =
879 GenerateUnmappedArgumentsLookup(masm, r2, r3, r4, &slow);
880 __ ldr(r1, unmapped_location);
881 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
882 __ cmp(r1, r3);
883 __ b(eq, &slow);
884 GenerateFunctionTailCall(masm, argc, &slow, r3);
885 __ bind(&slow);
886 GenerateMiss(masm, argc);
887}
888
889
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000890void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000891 // ---------- S t a t e --------------
892 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000893 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000894 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000895 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000896 Isolate* isolate = masm->isolate();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000897
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000898 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000899
ager@chromium.orgac091b72010-05-05 07:34:42 +0000900 __ Push(r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000901
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000902 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000903 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000904 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
905 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
906
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000907 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000908}
909
910
911void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
912 // ---------- S t a t e --------------
913 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000914 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000915 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000916 // -----------------------------------
917
ager@chromium.orgac091b72010-05-05 07:34:42 +0000918 __ Push(r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000919
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000920 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921}
922
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000923
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000925 // ---------- S t a t e --------------
926 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000927 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000928 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000929 // -----------------------------------
ulan@chromium.org750145a2013-03-07 15:14:13 +0000930 Label slow, check_name, index_smi, index_name, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000931 Label probe_dictionary, check_number_dictionary;
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000932
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000933 Register key = r0;
934 Register receiver = r1;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000935
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000936 Isolate* isolate = masm->isolate();
937
ager@chromium.org5c838252010-02-19 08:53:10 +0000938 // Check that the key is a smi.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000939 __ JumpIfNotSmi(key, &check_name);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000940 __ bind(&index_smi);
941 // Now the key is known to be a smi. This place is also jumped to from below
942 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000943
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000944 GenerateKeyedLoadReceiverCheck(
945 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
946
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000947 // Check the receiver's map to see if it has fast elements.
948 __ CheckFastElements(r2, r3, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000949
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000950 GenerateFastArrayLoad(
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000951 masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000952 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000953 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000954
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000955 __ bind(&check_number_dictionary);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000956 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
957 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
958
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959 // Check whether the elements is a number dictionary.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000960 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000961 // r3: elements map
962 // r4: elements
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000963 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
964 __ cmp(r3, ip);
965 __ b(ne, &slow);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000966 __ SmiUntag(r2, r0);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000967 __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000968 __ Ret();
969
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000970 // Slow case, key and receiver still in r0 and r1.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000971 __ bind(&slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000972 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
973 1, r2, r3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000974 GenerateRuntimeGetProperty(masm);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000975
ulan@chromium.org750145a2013-03-07 15:14:13 +0000976 __ bind(&check_name);
977 GenerateKeyNameCheck(masm, key, r2, r3, &index_name, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000978
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000979 GenerateKeyedLoadReceiverCheck(
980 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
981
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000982 // If the receiver is a fast-case object, check the keyed lookup
983 // cache. Otherwise probe the dictionary.
984 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000985 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000986 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000987 __ cmp(r4, ip);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000988 __ b(eq, &probe_dictionary);
989
990 // Load the map of the receiver, compute the keyed lookup cache hash
ulan@chromium.org750145a2013-03-07 15:14:13 +0000991 // based on 32 bits of the map pointer and the name hash.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000992 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
993 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
ulan@chromium.org750145a2013-03-07 15:14:13 +0000994 __ ldr(r4, FieldMemOperand(r0, Name::kHashFieldOffset));
995 __ eor(r3, r3, Operand(r4, ASR, Name::kHashShift));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000996 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
997 __ And(r3, r3, Operand(mask));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000998
ulan@chromium.org750145a2013-03-07 15:14:13 +0000999 // Load the key (consisting of map and unique name) from the cache and
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001000 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001001 Label load_in_object_property;
1002 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
1003 Label hit_on_nth_entry[kEntriesPerBucket];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001004 ExternalReference cache_keys =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001005 ExternalReference::keyed_lookup_cache_keys(isolate);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001006
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001007 __ mov(r4, Operand(cache_keys));
1008 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001009
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001010 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
1011 Label try_next_entry;
1012 // Load map and move r4 to next entry.
1013 __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex));
1014 __ cmp(r2, r5);
1015 __ b(ne, &try_next_entry);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001016 __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load name
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001017 __ cmp(r0, r5);
1018 __ b(eq, &hit_on_nth_entry[i]);
1019 __ bind(&try_next_entry);
1020 }
1021
ulan@chromium.org750145a2013-03-07 15:14:13 +00001022 // Last entry: Load map and move r4 to name.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001023 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001024 __ cmp(r2, r5);
1025 __ b(ne, &slow);
1026 __ ldr(r5, MemOperand(r4));
1027 __ cmp(r0, r5);
1028 __ b(ne, &slow);
1029
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001030 // Get field offset.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001031 // r0 : key
1032 // r1 : receiver
1033 // r2 : receiver's map
1034 // r3 : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 ExternalReference cache_field_offsets =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001036 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001037
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001038 // Hit on nth entry.
1039 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
1040 __ bind(&hit_on_nth_entry[i]);
1041 __ mov(r4, Operand(cache_field_offsets));
1042 if (i != 0) {
1043 __ add(r3, r3, Operand(i));
1044 }
1045 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1046 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
1047 __ sub(r5, r5, r6, SetCC);
1048 __ b(ge, &property_array_property);
1049 if (i != 0) {
1050 __ jmp(&load_in_object_property);
1051 }
1052 }
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001053
1054 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001055 __ bind(&load_in_object_property);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001056 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1057 __ add(r6, r6, r5); // Index from start of object.
1058 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1059 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001060 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1061 1, r2, r3);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001062 __ Ret();
1063
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001064 // Load property array property.
1065 __ bind(&property_array_property);
1066 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1067 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1068 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001069 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1070 1, r2, r3);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001071 __ Ret();
1072
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001073 // Do a quick inline probe of the receiver's dictionary, if it
1074 // exists.
1075 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001076 // r1: receiver
1077 // r0: key
1078 // r3: elements
1079 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1080 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1081 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001082 // Load the property to r0.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001083 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001084 __ IncrementCounter(
1085 isolate->counters()->keyed_load_generic_symbol(), 1, r2, r3);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001086 __ Ret();
1087
ulan@chromium.org750145a2013-03-07 15:14:13 +00001088 __ bind(&index_name);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001089 __ IndexFromHash(r3, key);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001090 // Now jump to the place where smi keys are handled.
1091 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092}
1093
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001094
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001095void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1096 // ---------- S t a t e --------------
1097 // -- lr : return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001098 // -- r0 : key (index)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001099 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001100 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001101 Label miss;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001102
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001103 Register receiver = r1;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001104 Register index = r0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001105 Register scratch = r3;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001106 Register result = r0;
ager@chromium.org357bf652010-04-12 11:30:10 +00001107
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 StringCharAtGenerator char_at_generator(receiver,
1109 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001110 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001111 result,
1112 &miss, // When not a string.
1113 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001114 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001115 STRING_INDEX_IS_ARRAY_INDEX);
1116 char_at_generator.GenerateFast(masm);
1117 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +00001118
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001119 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001120 char_at_generator.GenerateSlow(masm, call_helper);
ager@chromium.org357bf652010-04-12 11:30:10 +00001121
ager@chromium.org357bf652010-04-12 11:30:10 +00001122 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001123 GenerateMiss(masm, MISS);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001124}
1125
1126
ager@chromium.org5c838252010-02-19 08:53:10 +00001127void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1128 // ---------- S t a t e --------------
1129 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001130 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001131 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001132 // -----------------------------------
1133 Label slow;
1134
ager@chromium.org5c838252010-02-19 08:53:10 +00001135 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001136 __ JumpIfSmi(r1, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001137
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001138 // Check that the key is an array index, that is Uint32.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001139 __ NonNegativeSmiTst(r0);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001140 __ b(ne, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001141
1142 // Get the map of the receiver.
1143 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1144
1145 // Check that it has indexed interceptor and access checks
1146 // are not enabled for this object.
1147 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1148 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1149 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1150 __ b(ne, &slow);
1151
1152 // Everything is fine, call runtime.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001153 __ Push(r1, r0); // Receiver, key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001154
1155 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 __ TailCallExternalReference(
1157 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
1158 masm->isolate()),
1159 2,
1160 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001161
1162 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001163 GenerateMiss(masm, MISS);
ager@chromium.org5c838252010-02-19 08:53:10 +00001164}
1165
1166
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001167void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001168 // ---------- S t a t e --------------
1169 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001170 // -- r1 : key
1171 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001172 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001173 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001174
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001175 // Push receiver, key and value for runtime call.
1176 __ Push(r2, r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001177
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001178 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001179 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1180 masm->isolate())
1181 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1182 __ TailCallExternalReference(ref, 3, 1);
1183}
1184
1185
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001186void StoreIC::GenerateSlow(MacroAssembler* masm) {
1187 // ---------- S t a t e --------------
1188 // -- r0 : value
1189 // -- r2 : key
1190 // -- r1 : receiver
1191 // -- lr : return address
1192 // -----------------------------------
1193
1194 // Push receiver, key and value for runtime call.
1195 __ Push(r1, r2, r0);
1196
1197 // The slow case calls into the runtime to complete the store without causing
1198 // an IC miss that would otherwise cause a transition to the generic stub.
1199 ExternalReference ref =
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001200 ExternalReference(IC_Utility(kStoreIC_Slow), masm->isolate());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001201 __ TailCallExternalReference(ref, 3, 1);
1202}
1203
1204
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001205void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1206 // ---------- S t a t e --------------
1207 // -- r0 : value
1208 // -- r1 : key
1209 // -- r2 : receiver
1210 // -- lr : return address
1211 // -----------------------------------
1212
1213 // Push receiver, key and value for runtime call.
1214 __ Push(r2, r1, r0);
1215
1216 // The slow case calls into the runtime to complete the store without causing
1217 // an IC miss that would otherwise cause a transition to the generic stub.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001218 ExternalReference ref =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001219 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001220 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001221}
1222
1223
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001224void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1225 StrictModeFlag strict_mode) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001226 // ---------- S t a t e --------------
1227 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001228 // -- r1 : key
1229 // -- r2 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001230 // -- lr : return address
ager@chromium.org5c838252010-02-19 08:53:10 +00001231 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001232
1233 // Push receiver, key and value for runtime call.
1234 __ Push(r2, r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001235
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001236 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1237 __ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1238 __ Push(r1, r0);
1239
1240 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241}
1242
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001243
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001244static void KeyedStoreGenerateGenericHelper(
1245 MacroAssembler* masm,
1246 Label* fast_object,
1247 Label* fast_double,
1248 Label* slow,
1249 KeyedStoreCheckMap check_map,
1250 KeyedStoreIncrementLength increment_length,
1251 Register value,
1252 Register key,
1253 Register receiver,
1254 Register receiver_map,
1255 Register elements_map,
1256 Register elements) {
1257 Label transition_smi_elements;
1258 Label finish_object_store, non_double_value, transition_double_elements;
1259 Label fast_double_without_map_check;
1260
1261 // Fast case: Do the store, could be either Object or double.
1262 __ bind(fast_object);
1263 Register scratch_value = r4;
1264 Register address = r5;
1265 if (check_map == kCheckMap) {
1266 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1267 __ cmp(elements_map,
1268 Operand(masm->isolate()->factory()->fixed_array_map()));
1269 __ b(ne, fast_double);
1270 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001271
1272 // HOLECHECK: guards "A[i] = V"
1273 // We have to go to the runtime if the current value is the hole because
1274 // there may be a callback on the element
1275 Label holecheck_passed1;
1276 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1277 __ ldr(scratch_value,
1278 MemOperand::PointerAddressFromSmiKey(address, key, PreIndex));
1279 __ cmp(scratch_value, Operand(masm->isolate()->factory()->the_hole_value()));
1280 __ b(ne, &holecheck_passed1);
1281 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
1282 slow);
1283
1284 __ bind(&holecheck_passed1);
1285
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001286 // Smi stores don't require further checks.
1287 Label non_smi_value;
1288 __ JumpIfNotSmi(value, &non_smi_value);
1289
1290 if (increment_length == kIncrementLength) {
1291 // Add 1 to receiver->length.
1292 __ add(scratch_value, key, Operand(Smi::FromInt(1)));
1293 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1294 }
1295 // It's irrelevant whether array is smi-only or not when writing a smi.
1296 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001297 __ str(value, MemOperand::PointerAddressFromSmiKey(address, key));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001298 __ Ret();
1299
1300 __ bind(&non_smi_value);
1301 // Escape to elements kind transition case.
1302 __ CheckFastObjectElements(receiver_map, scratch_value,
1303 &transition_smi_elements);
1304
1305 // Fast elements array, store the value to the elements backing store.
1306 __ bind(&finish_object_store);
1307 if (increment_length == kIncrementLength) {
1308 // Add 1 to receiver->length.
1309 __ add(scratch_value, key, Operand(Smi::FromInt(1)));
1310 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1311 }
1312 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001313 __ add(address, address, Operand::PointerOffsetFromSmiKey(key));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001314 __ str(value, MemOperand(address));
1315 // Update write barrier for the elements array address.
1316 __ mov(scratch_value, value); // Preserve the value which is returned.
1317 __ RecordWrite(elements,
1318 address,
1319 scratch_value,
1320 kLRHasNotBeenSaved,
1321 kDontSaveFPRegs,
1322 EMIT_REMEMBERED_SET,
1323 OMIT_SMI_CHECK);
1324 __ Ret();
1325
1326 __ bind(fast_double);
1327 if (check_map == kCheckMap) {
1328 // Check for fast double array case. If this fails, call through to the
1329 // runtime.
1330 __ CompareRoot(elements_map, Heap::kFixedDoubleArrayMapRootIndex);
1331 __ b(ne, slow);
1332 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001333
1334 // HOLECHECK: guards "A[i] double hole?"
1335 // We have to see if the double version of the hole is present. If so
1336 // go to the runtime.
1337 __ add(address, elements,
1338 Operand((FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32))
1339 - kHeapObjectTag));
1340 __ ldr(scratch_value,
1341 MemOperand(address, key, LSL, kPointerSizeLog2, PreIndex));
1342 __ cmp(scratch_value, Operand(kHoleNanUpper32));
1343 __ b(ne, &fast_double_without_map_check);
1344 __ JumpIfDictionaryInPrototypeChain(receiver, elements_map, scratch_value,
1345 slow);
1346
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001347 __ bind(&fast_double_without_map_check);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001348 __ StoreNumberToDoubleElements(value, key, elements, r3, d0,
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001349 &transition_double_elements);
1350 if (increment_length == kIncrementLength) {
1351 // Add 1 to receiver->length.
1352 __ add(scratch_value, key, Operand(Smi::FromInt(1)));
1353 __ str(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1354 }
1355 __ Ret();
1356
1357 __ bind(&transition_smi_elements);
1358 // Transition the array appropriately depending on the value type.
1359 __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
1360 __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
1361 __ b(ne, &non_double_value);
1362
1363 // Value is a double. Transition FAST_SMI_ELEMENTS ->
1364 // FAST_DOUBLE_ELEMENTS and complete the store.
1365 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1366 FAST_DOUBLE_ELEMENTS,
1367 receiver_map,
1368 r4,
1369 slow);
1370 ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
danno@chromium.orgbee51992013-07-10 14:57:15 +00001371 AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
1372 FAST_DOUBLE_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001373 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001374 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1375 __ jmp(&fast_double_without_map_check);
1376
1377 __ bind(&non_double_value);
1378 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
1379 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1380 FAST_ELEMENTS,
1381 receiver_map,
1382 r4,
1383 slow);
1384 ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
danno@chromium.orgbee51992013-07-10 14:57:15 +00001385 mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001386 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
1387 slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001388 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1389 __ jmp(&finish_object_store);
1390
1391 __ bind(&transition_double_elements);
1392 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
1393 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
1394 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1395 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1396 FAST_ELEMENTS,
1397 receiver_map,
1398 r4,
1399 slow);
1400 ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
danno@chromium.orgbee51992013-07-10 14:57:15 +00001401 mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001402 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001403 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1404 __ jmp(&finish_object_store);
1405}
1406
1407
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1409 StrictModeFlag strict_mode) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001410 // ---------- S t a t e --------------
1411 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001412 // -- r1 : key
1413 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001414 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001415 // -----------------------------------
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001416 Label slow, fast_object, fast_object_grow;
1417 Label fast_double, fast_double_grow;
1418 Label array, extra, check_if_double_array;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001419
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001420 // Register usage.
1421 Register value = r0;
1422 Register key = r1;
1423 Register receiver = r2;
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00001424 Register receiver_map = r3;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001425 Register elements_map = r6;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001426 Register elements = r9; // Elements array of the receiver.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001427 // r4 and r5 are used as general scratch registers.
1428
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001429 // Check that the key is a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001430 __ JumpIfNotSmi(key, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001431 // Check that the object isn't a smi.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001432 __ JumpIfSmi(receiver, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001433 // Get the map of the object.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001434 __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001435 // Check that the receiver does not require access checks and is not observed.
1436 // The generic stub does not perform map checks or handle observed objects.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001437 __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001438 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded | 1 << Map::kIsObserved));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001439 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001440 // Check if the object is a JS array or not.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001441 __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001442 __ cmp(r4, Operand(JS_ARRAY_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001443 __ b(eq, &array);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001444 // Check that the object is some kind of JSObject.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001446 __ b(lt, &slow);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001447
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001448 // Object case: Check key against length in the elements array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001449 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001450 // Check array bounds. Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001451 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001452 __ cmp(key, Operand(ip));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001453 __ b(lo, &fast_object);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001454
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001455 // Slow case, handle jump to runtime.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001456 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001457 // Entry registers are intact.
1458 // r0: value.
1459 // r1: key.
1460 // r2: receiver.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001461 GenerateRuntimeSetProperty(masm, strict_mode);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001462
1463 // Extra capacity case: Check if there is extra capacity to
1464 // perform the store and update the length. Used for adding one
1465 // element to the array by writing to array[array.length].
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001466 __ bind(&extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001467 // Condition code from comparing key and array length is still available.
1468 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1469 // Check for room in the elements backing store.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001470 // Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001471 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001472 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001473 __ b(hs, &slow);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001474 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1475 __ cmp(elements_map,
1476 Operand(masm->isolate()->factory()->fixed_array_map()));
1477 __ b(ne, &check_if_double_array);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001478 __ jmp(&fast_object_grow);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001479
1480 __ bind(&check_if_double_array);
1481 __ cmp(elements_map,
1482 Operand(masm->isolate()->factory()->fixed_double_array_map()));
1483 __ b(ne, &slow);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001484 __ jmp(&fast_double_grow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001485
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001486 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001487 // array. Check that the array is in fast mode (and writable); if it
1488 // is the length is always a smi.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001489 __ bind(&array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001490 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001491
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001492 // Check the key against the length in the array.
1493 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1494 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001495 __ b(hs, &extra);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001496
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001497 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
1498 &slow, kCheckMap, kDontIncrementLength,
1499 value, key, receiver, receiver_map,
1500 elements_map, elements);
1501 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
1502 &slow, kDontCheckMap, kIncrementLength,
1503 value, key, receiver, receiver_map,
1504 elements_map, elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001505}
1506
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001507
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001508void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001509 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510 // ----------- S t a t e -------------
1511 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001512 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513 // -- r2 : name
1514 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 // -----------------------------------
1516
1517 // Get the receiver from the stack and probe the stub cache.
danno@chromium.orgbee51992013-07-10 14:57:15 +00001518 Code::Flags flags = Code::ComputeFlags(
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +00001519 Code::HANDLER, MONOMORPHIC, strict_mode,
danno@chromium.orgbee51992013-07-10 14:57:15 +00001520 Code::NORMAL, Code::STORE_IC);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001521
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00001522 masm->isolate()->stub_cache()->GenerateProbe(
ulan@chromium.org812308e2012-02-29 15:58:45 +00001523 masm, flags, r1, r2, r3, r4, r5, r6);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001526 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527}
1528
1529
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001530void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 // ----------- S t a t e -------------
1532 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001533 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 // -- r2 : name
1535 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 // -----------------------------------
1537
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001538 __ Push(r1, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001539
mads.s.ager31e71382008-08-13 09:32:07 +00001540 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 ExternalReference ref =
1542 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001543 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544}
1545
1546
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001547void StoreIC::GenerateNormal(MacroAssembler* masm) {
1548 // ----------- S t a t e -------------
1549 // -- r0 : value
1550 // -- r1 : receiver
1551 // -- r2 : name
1552 // -- lr : return address
1553 // -----------------------------------
1554 Label miss;
1555
ulan@chromium.org750145a2013-03-07 15:14:13 +00001556 GenerateNameDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001557
1558 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001559 Counters* counters = masm->isolate()->counters();
1560 __ IncrementCounter(counters->store_normal_hit(),
1561 1, r4, r5);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001562 __ Ret();
1563
1564 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001565 __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001566 GenerateMiss(masm);
1567}
1568
1569
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001570void StoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1571 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001572 // ----------- S t a t e -------------
1573 // -- r0 : value
1574 // -- r1 : receiver
1575 // -- r2 : name
1576 // -- lr : return address
1577 // -----------------------------------
1578
1579 __ Push(r1, r2, r0);
1580
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001581 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1582 __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1583 __ Push(r1, r0);
1584
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001585 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001586 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001587}
1588
1589
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001590#undef __
1591
1592
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001593Condition CompareIC::ComputeCondition(Token::Value op) {
1594 switch (op) {
1595 case Token::EQ_STRICT:
1596 case Token::EQ:
1597 return eq;
1598 case Token::LT:
1599 return lt;
1600 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001601 return gt;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001602 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001603 return le;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001604 case Token::GTE:
1605 return ge;
1606 default:
1607 UNREACHABLE();
ager@chromium.org378b34e2011-01-28 08:04:38 +00001608 return kNoCondition;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001609 }
1610}
1611
1612
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001613bool CompareIC::HasInlinedSmiCode(Address address) {
1614 // The address of the instruction following the call.
1615 Address cmp_instruction_address =
1616 Assembler::return_address_from_call_start(address);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001617
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001618 // If the instruction following the call is not a cmp rx, #yyy, nothing
1619 // was inlined.
1620 Instr instr = Assembler::instr_at(cmp_instruction_address);
1621 return Assembler::IsCmpImmediate(instr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001622}
1623
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001624
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001625void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001626 Address cmp_instruction_address =
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001627 Assembler::return_address_from_call_start(address);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001628
1629 // If the instruction following the call is not a cmp rx, #yyy, nothing
1630 // was inlined.
1631 Instr instr = Assembler::instr_at(cmp_instruction_address);
1632 if (!Assembler::IsCmpImmediate(instr)) {
1633 return;
1634 }
1635
1636 // The delta to the start of the map check instruction and the
1637 // condition code uses at the patched jump.
1638 int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1639 delta +=
1640 Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1641 // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1642 // nothing was inlined.
1643 if (delta == 0) {
1644 return;
1645 }
1646
1647#ifdef DEBUG
1648 if (FLAG_trace_ic) {
1649 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
1650 address, cmp_instruction_address, delta);
1651 }
1652#endif
1653
1654 Address patch_address =
1655 cmp_instruction_address - delta * Instruction::kInstrSize;
1656 Instr instr_at_patch = Assembler::instr_at(patch_address);
1657 Instr branch_instr =
1658 Assembler::instr_at(patch_address + Instruction::kInstrSize);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001659 // This is patching a conditional "jump if not smi/jump if smi" site.
1660 // Enabling by changing from
1661 // cmp rx, rx
1662 // b eq/ne, <target>
1663 // to
1664 // tst rx, #kSmiTagMask
1665 // b ne/eq, <target>
1666 // and vice-versa to be disabled again.
1667 CodePatcher patcher(patch_address, 2);
1668 Register reg = Assembler::GetRn(instr_at_patch);
1669 if (check == ENABLE_INLINED_SMI_CHECK) {
1670 ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1671 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1672 Assembler::GetRm(instr_at_patch).code());
1673 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1674 } else {
1675 ASSERT(check == DISABLE_INLINED_SMI_CHECK);
1676 ASSERT(Assembler::IsTstImmediate(instr_at_patch));
1677 patcher.masm()->cmp(reg, reg);
1678 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001679 ASSERT(Assembler::IsBranch(branch_instr));
1680 if (Assembler::GetCondition(branch_instr) == eq) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001681 patcher.EmitCondition(ne);
1682 } else {
1683 ASSERT(Assembler::GetCondition(branch_instr) == ne);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001684 patcher.EmitCondition(eq);
1685 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001686}
1687
1688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001690
1691#endif // V8_TARGET_ARCH_ARM