blob: 8749eea5b247ccc1f1a80562f302112f5653cc2a [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_ARM)
31
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.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +000067static void GenerateStringDictionaryReceiverCheck(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.
82 __ tst(receiver, Operand(kSmiTagMask));
83 __ b(eq, miss);
84
85 // Check that the receiver is a valid JS object.
86 __ CompareObjectType(receiver, t0, t1, FIRST_JS_OBJECT_TYPE);
87 __ b(lt, miss);
88
89 // If this assert fails, we have to check upper bound too.
90 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
91
92 GenerateGlobalInstanceTypeCheck(masm, t1, miss);
93
94 // Check that the global object does not require access checks.
95 __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
96 __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
97 (1 << Map::kHasNamedInterceptor)));
ager@chromium.org378b34e2011-01-28 08:04:38 +000098 __ b(ne, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000099
100 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
101 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
102 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
103 __ cmp(t1, ip);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000104 __ b(ne, miss);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000105}
106
107
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000108// Helper function used from LoadIC/CallIC GenerateNormal.
109//
110// elements: Property dictionary. It is not clobbered if a jump to the miss
111// label is done.
112// name: Property name. It is not clobbered if a jump to the miss label is
113// done
114// result: Register for the result. It is only updated if a jump to the miss
115// label is not done. Can be the same as elements or name clobbering
116// one of these in the case of not jumping to the miss label.
117// The two scratch registers need to be different from elements, name and
118// result.
119// The generated code assumes that the receiver has slow properties,
120// is not a global object and does not have interceptors.
121static void GenerateDictionaryLoad(MacroAssembler* masm,
122 Label* miss,
123 Register elements,
124 Register name,
125 Register result,
126 Register scratch1,
127 Register scratch2) {
128 // Main use of the scratch registers.
129 // scratch1: Used as temporary and to hold the capacity of the property
130 // dictionary.
131 // scratch2: Used as temporary.
132 Label done;
133
134 // Probe the dictionary.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000135 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
136 miss,
137 &done,
138 elements,
139 name,
140 scratch1,
141 scratch2);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000142
143 // If probing finds an entry check that the value is a normal
144 // property.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000145 __ bind(&done); // scratch2 == elements + 4 * index
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000146 const int kElementsStartOffset = StringDictionary::kHeaderSize +
147 StringDictionary::kElementsStartIndex * kPointerSize;
148 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
149 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000150 __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000151 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152
153 // Get the value at the masked, scaled index and return.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000154 __ ldr(result,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000155 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156}
157
158
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000159// Helper function used from StoreIC::GenerateNormal.
160//
161// elements: Property dictionary. It is not clobbered if a jump to the miss
162// label is done.
163// name: Property name. It is not clobbered if a jump to the miss label is
164// done
165// value: The value to store.
166// The two scratch registers need to be different from elements, name and
167// result.
168// The generated code assumes that the receiver has slow properties,
169// is not a global object and does not have interceptors.
170static void GenerateDictionaryStore(MacroAssembler* masm,
171 Label* miss,
172 Register elements,
173 Register name,
174 Register value,
175 Register scratch1,
176 Register scratch2) {
177 // Main use of the scratch registers.
178 // scratch1: Used as temporary and to hold the capacity of the property
179 // dictionary.
180 // scratch2: Used as temporary.
181 Label done;
182
183 // Probe the dictionary.
lrn@chromium.org1c092762011-05-09 09:42:16 +0000184 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
185 miss,
186 &done,
187 elements,
188 name,
189 scratch1,
190 scratch2);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000191
192 // If probing finds an entry in the dictionary check that the value
193 // is a normal property that is not read only.
194 __ bind(&done); // scratch2 == elements + 4 * index
195 const int kElementsStartOffset = StringDictionary::kHeaderSize +
196 StringDictionary::kElementsStartIndex * kPointerSize;
197 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
198 const int kTypeAndReadOnlyMask
199 = (PropertyDetails::TypeField::mask() |
200 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
201 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
202 __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
203 __ b(ne, miss);
204
205 // Store the value at the masked, scaled index and return.
206 const int kValueOffset = kElementsStartOffset + kPointerSize;
207 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
208 __ str(value, MemOperand(scratch2));
209
210 // Update the write barrier. Make sure not to clobber the value.
211 __ mov(scratch1, value);
212 __ RecordWrite(elements, scratch2, scratch1);
213}
214
215
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000216static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
217 Label* miss,
218 Register elements,
219 Register key,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000220 Register result,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000221 Register t0,
222 Register t1,
223 Register t2) {
224 // Register use:
225 //
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000226 // elements - holds the slow-case elements of the receiver on entry.
227 // Unchanged unless 'result' is the same register.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000228 //
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000229 // key - holds the smi key on entry.
230 // Unchanged unless 'result' is the same register.
231 //
232 // result - holds the result on exit if the load succeeded.
233 // Allowed to be the same as 'key' or 'result'.
234 // Unchanged on bailout so 'key' or 'result' can be used
235 // in further computation.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000236 //
237 // Scratch registers:
238 //
239 // t0 - holds the untagged key on entry and holds the hash once computed.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000240 //
241 // t1 - used to hold the capacity mask of the dictionary
242 //
243 // t2 - used for the index into the dictionary.
244 Label done;
245
246 // Compute the hash code from the untagged key. This must be kept in sync
247 // with ComputeIntegerHash in utils.h.
248 //
249 // hash = ~hash + (hash << 15);
250 __ mvn(t1, Operand(t0));
251 __ add(t0, t1, Operand(t0, LSL, 15));
252 // hash = hash ^ (hash >> 12);
253 __ eor(t0, t0, Operand(t0, LSR, 12));
254 // hash = hash + (hash << 2);
255 __ add(t0, t0, Operand(t0, LSL, 2));
256 // hash = hash ^ (hash >> 4);
257 __ eor(t0, t0, Operand(t0, LSR, 4));
258 // hash = hash * 2057;
259 __ mov(t1, Operand(2057));
260 __ mul(t0, t0, t1);
261 // hash = hash ^ (hash >> 16);
262 __ eor(t0, t0, Operand(t0, LSR, 16));
263
264 // Compute the capacity mask.
265 __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
266 __ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
267 __ sub(t1, t1, Operand(1));
268
269 // Generate an unrolled loop that performs a few probes before giving up.
270 static const int kProbes = 4;
271 for (int i = 0; i < kProbes; i++) {
272 // Use t2 for index calculations and keep the hash intact in t0.
273 __ mov(t2, t0);
274 // Compute the masked index: (hash + i + i * i) & mask.
275 if (i > 0) {
276 __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
277 }
278 __ and_(t2, t2, Operand(t1));
279
280 // Scale the index by multiplying by the element size.
281 ASSERT(NumberDictionary::kEntrySize == 3);
282 __ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
283
284 // Check if the key is identical to the name.
285 __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
286 __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
287 __ cmp(key, Operand(ip));
288 if (i != kProbes - 1) {
289 __ b(eq, &done);
290 } else {
291 __ b(ne, miss);
292 }
293 }
294
295 __ bind(&done);
296 // Check that the value is a normal property.
297 // t2: elements + (index * kPointerSize)
298 const int kDetailsOffset =
299 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
300 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
301 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
302 __ b(ne, miss);
303
304 // Get the value at the masked, scaled index and return.
305 const int kValueOffset =
306 NumberDictionary::kElementsStartOffset + kPointerSize;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000307 __ ldr(result, FieldMemOperand(t2, kValueOffset));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000308}
309
310
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
312 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 // -- r2 : name
314 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000315 // -- r0 : receiver
316 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000317 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318 Label miss;
319
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000320 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000322 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323}
324
325
ager@chromium.org378b34e2011-01-28 08:04:38 +0000326void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328 // -- r2 : name
329 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000330 // -- r0 : receiver
331 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000333 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334
ager@chromium.org378b34e2011-01-28 08:04:38 +0000335 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
336 support_wrappers);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 // Cache miss: Jump to runtime.
338 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000339 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000340}
341
342
343void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
344 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345 // -- r2 : name
346 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000347 // -- r0 : receiver
348 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 // -----------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000350 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000352 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
353 __ bind(&miss);
354 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355}
356
357
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000358// Checks the receiver for special cases (value type, slow case bits).
359// Falls through for regular JS object.
360static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
361 Register receiver,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000362 Register map,
363 Register scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000364 int interceptor_bit,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000365 Label* slow) {
366 // Check that the object isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000367 __ JumpIfSmi(receiver, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000368 // Get the map of the receiver.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000369 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000370 // Check bit field.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000371 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
372 __ tst(scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000373 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000374 __ b(ne, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000375 // Check that the object is some kind of JS object EXCEPT JS Value type.
376 // In the case that the object is a value-wrapper object,
377 // we enter the runtime system to make sure that indexing into string
378 // objects work as intended.
379 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000380 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
381 __ cmp(scratch, Operand(JS_OBJECT_TYPE));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000382 __ b(lt, slow);
383}
384
385
386// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000387// If not_fast_array is NULL, doesn't perform the elements map check.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000388static void GenerateFastArrayLoad(MacroAssembler* masm,
389 Register receiver,
390 Register key,
391 Register elements,
392 Register scratch1,
393 Register scratch2,
394 Register result,
395 Label* not_fast_array,
396 Label* out_of_range) {
397 // Register use:
398 //
399 // receiver - holds the receiver on entry.
400 // Unchanged unless 'result' is the same register.
401 //
402 // key - holds the smi key on entry.
403 // Unchanged unless 'result' is the same register.
404 //
405 // elements - holds the elements of the receiver on exit.
406 //
407 // result - holds the result on exit if the load succeeded.
408 // Allowed to be the the same as 'receiver' or 'key'.
409 // Unchanged on bailout so 'receiver' and 'key' can be safely
410 // used by further computation.
411 //
412 // Scratch registers:
413 //
414 // scratch1 - used to hold elements map and elements length.
415 // Holds the elements map if not_fast_array branch is taken.
416 //
417 // scratch2 - used to hold the loaded value.
418
419 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000420 if (not_fast_array != NULL) {
421 // Check that the object is in fast mode and writable.
422 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
423 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
424 __ cmp(scratch1, ip);
425 __ b(ne, not_fast_array);
426 } else {
427 __ AssertFastElements(elements);
428 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000429 // Check that the key (index) is within bounds.
430 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
431 __ cmp(key, Operand(scratch1));
432 __ b(hs, out_of_range);
433 // Fast case: Do the load.
434 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
435 // The key is a smi.
436 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
437 __ ldr(scratch2,
438 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
439 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
440 __ cmp(scratch2, ip);
441 // In case the loaded value is the_hole we have to consult GetProperty
442 // to ensure the prototype chain is searched.
443 __ b(eq, out_of_range);
444 __ mov(result, scratch2);
445}
446
447
448// Checks whether a key is an array index string or a symbol string.
449// Falls through if a key is a symbol.
450static void GenerateKeyStringCheck(MacroAssembler* masm,
451 Register key,
452 Register map,
453 Register hash,
454 Label* index_string,
455 Label* not_symbol) {
456 // The key is not a smi.
457 // Is it a string?
458 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
459 __ b(ge, not_symbol);
460
461 // Is the string an array index, with cached numeric value?
462 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
463 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
464 __ b(eq, index_string);
465
466 // Is the string a symbol?
467 // map: key map
468 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
469 ASSERT(kSymbolTag != 0);
470 __ tst(hash, Operand(kIsSymbolMask));
471 __ b(eq, not_symbol);
472}
473
474
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475// Defined in ic.cc.
476Object* CallIC_Miss(Arguments args);
477
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000478// The generated code does not accept smi keys.
479// The generated code falls through if both probes miss.
480static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
481 int argc,
482 Code::Kind kind) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483 // ----------- S t a t e -------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000484 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000485 // -- r2 : name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486 // -----------------------------------
487 Label number, non_number, non_string, boolean, probe, miss;
488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000489 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000490 Code::Flags flags = Code::ComputeFlags(kind,
491 NOT_IN_LOOP,
492 MONOMORPHIC,
493 Code::kNoExtraICState,
494 NORMAL,
495 argc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000496 Isolate::Current()->stub_cache()->GenerateProbe(
497 masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498
499 // If the stub cache probing failed, the receiver might be a value.
500 // For value objects, we use the map of the prototype objects for
501 // the corresponding JSValue for the cache and that is what we need
502 // to probe.
503 //
504 // Check for number.
505 __ tst(r1, Operand(kSmiTagMask));
506 __ b(eq, &number);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000507 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 __ b(ne, &non_number);
509 __ bind(&number);
510 StubCompiler::GenerateLoadGlobalFunctionPrototype(
511 masm, Context::NUMBER_FUNCTION_INDEX, r1);
512 __ b(&probe);
513
514 // Check for string.
515 __ bind(&non_number);
516 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
517 __ b(hs, &non_string);
518 StubCompiler::GenerateLoadGlobalFunctionPrototype(
519 masm, Context::STRING_FUNCTION_INDEX, r1);
520 __ b(&probe);
521
522 // Check for boolean.
523 __ bind(&non_string);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000524 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
525 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526 __ b(eq, &boolean);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000527 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
528 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529 __ b(ne, &miss);
530 __ bind(&boolean);
531 StubCompiler::GenerateLoadGlobalFunctionPrototype(
532 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
533
534 // Probe the stub cache for the value object.
535 __ bind(&probe);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000536 Isolate::Current()->stub_cache()->GenerateProbe(
537 masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000538
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540}
541
542
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000543static void GenerateFunctionTailCall(MacroAssembler* masm,
544 int argc,
545 Label* miss,
546 Register scratch) {
547 // r1: function
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000548
549 // Check that the value isn't a smi.
550 __ tst(r1, Operand(kSmiTagMask));
551 __ b(eq, miss);
552
553 // Check that the value is a JSFunction.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000554 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000555 __ b(ne, miss);
556
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000557 // Invoke the function.
558 ParameterCount actual(argc);
559 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
560}
561
562
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000563static void GenerateCallNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000565 // -- r2 : name
566 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000568 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569
mads.s.ager31e71382008-08-13 09:32:07 +0000570 // Get the receiver of the function from the stack into r1.
571 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000573 GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000575 // r0: elements
576 // Search the dictionary - put result in register r1.
577 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000579 GenerateFunctionTailCall(masm, argc, &miss, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000581 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000582}
583
584
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000585static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000586 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000587 // -- r2 : name
588 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000590 Isolate* isolate = masm->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000591
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000592 if (id == IC::kCallIC_Miss) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000593 __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000594 } else {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000595 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000596 }
597
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000598 // Get the receiver of the function from the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +0000599 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000600
601 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602
603 // Push the receiver and the name of the function.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000604 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000605
606 // Call the entry.
mads.s.ager31e71382008-08-13 09:32:07 +0000607 __ mov(r0, Operand(2));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000608 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609
ager@chromium.orga1645e22009-09-09 19:27:10 +0000610 CEntryStub stub(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 __ CallStub(&stub);
612
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000613 // Move result to r1 and leave the internal frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614 __ mov(r1, Operand(r0));
ager@chromium.org236ad962008-09-25 09:45:57 +0000615 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000617 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000618 // This can happen only for regular CallIC but not KeyedCallIC.
619 if (id == IC::kCallIC_Miss) {
620 Label invoke, global;
621 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
622 __ tst(r2, Operand(kSmiTagMask));
623 __ b(eq, &invoke);
624 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
625 __ b(eq, &global);
626 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
627 __ b(ne, &invoke);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000628
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000629 // Patch the receiver on the stack.
630 __ bind(&global);
631 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
632 __ str(r2, MemOperand(sp, argc * kPointerSize));
633 __ bind(&invoke);
634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000636 // Invoke the function.
637 ParameterCount actual(argc);
638 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639}
640
641
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000642void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
643 // ----------- S t a t e -------------
644 // -- r2 : name
645 // -- lr : return address
646 // -----------------------------------
647
648 GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
649}
650
651
652void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
653 // ----------- S t a t e -------------
654 // -- r2 : name
655 // -- lr : return address
656 // -----------------------------------
657
658 // Get the receiver of the function from the stack into r1.
659 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
660 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
661 GenerateMiss(masm, argc);
662}
663
664
665void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
666 // ----------- S t a t e -------------
667 // -- r2 : name
668 // -- lr : return address
669 // -----------------------------------
670
671 GenerateCallNormal(masm, argc);
672 GenerateMiss(masm, argc);
673}
674
675
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000676void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000677 // ----------- S t a t e -------------
678 // -- r2 : name
679 // -- lr : return address
680 // -----------------------------------
681
682 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000683}
684
685
686void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000687 // ----------- S t a t e -------------
688 // -- r2 : name
689 // -- lr : return address
690 // -----------------------------------
691
692 // Get the receiver of the function from the stack into r1.
693 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
694
695 Label do_call, slow_call, slow_load, slow_reload_receiver;
696 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
697 Label index_smi, index_string;
698
699 // Check that the key is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000700 __ JumpIfNotSmi(r2, &check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000701 __ bind(&index_smi);
702 // Now the key is known to be a smi. This place is also jumped to from below
703 // where a numeric string is converted to a smi.
704
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000705 GenerateKeyedLoadReceiverCheck(
706 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000707
708 GenerateFastArrayLoad(
709 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000710 Counters* counters = masm->isolate()->counters();
711 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000712
713 __ bind(&do_call);
714 // receiver in r1 is not used after this point.
715 // r2: key
716 // r1: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000717 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000718
719 __ bind(&check_number_dictionary);
720 // r2: key
721 // r3: elements map
722 // r4: elements
723 // Check whether the elements is a number dictionary.
724 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
725 __ cmp(r3, ip);
726 __ b(ne, &slow_load);
727 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
728 // r0: untagged index
729 GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000730 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000731 __ jmp(&do_call);
732
733 __ bind(&slow_load);
734 // This branch is taken when calling KeyedCallIC_Miss is neither required
735 // nor beneficial.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000736 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000737 __ EnterInternalFrame();
738 __ push(r2); // save the key
739 __ Push(r1, r2); // pass the receiver and the key
740 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
741 __ pop(r2); // restore the key
742 __ LeaveInternalFrame();
743 __ mov(r1, r0);
744 __ jmp(&do_call);
745
746 __ bind(&check_string);
747 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
748
749 // The key is known to be a symbol.
750 // If the receiver is a regular JS object with slow properties then do
751 // a quick inline probe of the receiver's dictionary.
752 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000753 GenerateKeyedLoadReceiverCheck(
754 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000755
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000756 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
757 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000758 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
759 __ cmp(r3, ip);
760 __ b(ne, &lookup_monomorphic_cache);
761
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000762 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000763 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000764 __ jmp(&do_call);
765
766 __ bind(&lookup_monomorphic_cache);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000767 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000768 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
769 // Fall through on miss.
770
771 __ bind(&slow_call);
772 // This branch is taken if:
773 // - the receiver requires boxing or access check,
774 // - the key is neither smi nor symbol,
775 // - the value loaded is not a function,
776 // - there is hope that the runtime will create a monomorphic call stub
777 // that will get fetched next time.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000778 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000779 GenerateMiss(masm, argc);
780
781 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000782 __ IndexFromHash(r3, r2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000783 // Now jump to the place where smi keys are handled.
784 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000785}
786
787
788void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000789 // ----------- S t a t e -------------
790 // -- r2 : name
791 // -- lr : return address
792 // -----------------------------------
793
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000794 // Check if the name is a string.
795 Label miss;
796 __ tst(r2, Operand(kSmiTagMask));
797 __ b(eq, &miss);
798 __ IsObjectJSStringType(r2, r0, &miss);
799
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000800 GenerateCallNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000801 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000802 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000803}
804
805
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806// Defined in ic.cc.
807Object* LoadIC_Miss(Arguments args);
808
809void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
810 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000811 // -- r2 : name
812 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000813 // -- r0 : receiver
814 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000815 // -----------------------------------
816
817 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000818 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
819 NOT_IN_LOOP,
820 MONOMORPHIC);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000821 Isolate::Current()->stub_cache()->GenerateProbe(
822 masm, flags, r0, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823
824 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +0000825 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826}
827
828
829void LoadIC::GenerateNormal(MacroAssembler* masm) {
830 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831 // -- r2 : name
832 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000833 // -- r0 : receiver
834 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000836 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000837
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000838 GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000840 // r1: elements
841 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 __ Ret();
843
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000844 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000846 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847}
848
849
850void LoadIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000852 // -- r2 : name
853 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000854 // -- r0 : receiver
855 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000857 Isolate* isolate = masm->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000859 __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000860
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000861 __ mov(r3, r0);
862 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863
mads.s.ager31e71382008-08-13 09:32:07 +0000864 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 ExternalReference ref =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000866 ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000867 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000868}
869
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000870
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000871void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000872 // ---------- S t a t e --------------
873 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000874 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000875 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000876 // -----------------------------------
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000877 Isolate* isolate = masm->isolate();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000878
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000879 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000880
ager@chromium.orgac091b72010-05-05 07:34:42 +0000881 __ Push(r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000882
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000883 // Perform tail call to the entry.
884 ExternalReference ref = force_generic
885 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
886 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
887
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000888 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000889}
890
891
892void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
893 // ---------- S t a t e --------------
894 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000895 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000896 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000897 // -----------------------------------
898
ager@chromium.orgac091b72010-05-05 07:34:42 +0000899 __ Push(r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000900
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000901 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902}
903
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000904
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000906 // ---------- S t a t e --------------
907 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000908 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000909 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000910 // -----------------------------------
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000911 Label slow, check_string, index_smi, index_string, property_array_property;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000912 Label probe_dictionary, check_number_dictionary;
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000913
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000914 Register key = r0;
915 Register receiver = r1;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000916
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000917 Isolate* isolate = masm->isolate();
918
ager@chromium.org5c838252010-02-19 08:53:10 +0000919 // Check that the key is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000920 __ JumpIfNotSmi(key, &check_string);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000921 __ bind(&index_smi);
922 // Now the key is known to be a smi. This place is also jumped to from below
923 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000924
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000925 GenerateKeyedLoadReceiverCheck(
926 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
927
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000928 // Check the "has fast elements" bit in the receiver's map which is
929 // now in r2.
930 __ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset));
931 __ tst(r3, Operand(1 << Map::kHasFastElements));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000932 __ b(eq, &check_number_dictionary);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000933
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000934 GenerateFastArrayLoad(
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000935 masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000936 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000937 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000938
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000939 __ bind(&check_number_dictionary);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000940 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
941 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
942
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000943 // Check whether the elements is a number dictionary.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000944 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000945 // r3: elements map
946 // r4: elements
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000947 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
948 __ cmp(r3, ip);
949 __ b(ne, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000950 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000951 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000952 __ Ret();
953
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000954 // Slow case, key and receiver still in r0 and r1.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000955 __ bind(&slow);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000956 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
957 1, r2, r3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000958 GenerateRuntimeGetProperty(masm);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000959
960 __ bind(&check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000961 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000962
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000963 GenerateKeyedLoadReceiverCheck(
964 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
965
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000966 // If the receiver is a fast-case object, check the keyed lookup
967 // cache. Otherwise probe the dictionary.
968 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000969 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000970 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000971 __ cmp(r4, ip);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000972 __ b(eq, &probe_dictionary);
973
974 // Load the map of the receiver, compute the keyed lookup cache hash
975 // based on 32 bits of the map pointer and the string hash.
976 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
977 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
978 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
979 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000980 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000981
982 // Load the key (consisting of map and symbol) from the cache and
983 // check for match.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 ExternalReference cache_keys =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000985 ExternalReference::keyed_lookup_cache_keys(isolate);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000986 __ mov(r4, Operand(cache_keys));
987 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
988 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
989 __ cmp(r2, r5);
990 __ b(ne, &slow);
991 __ ldr(r5, MemOperand(r4));
992 __ cmp(r0, r5);
993 __ b(ne, &slow);
994
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +0000995 // Get field offset.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000996 // r0 : key
997 // r1 : receiver
998 // r2 : receiver's map
999 // r3 : lookup cache index
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001000 ExternalReference cache_field_offsets =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001001 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001002 __ mov(r4, Operand(cache_field_offsets));
1003 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1004 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001005 __ sub(r5, r5, r6, SetCC);
1006 __ b(ge, &property_array_property);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001007
1008 // Load in-object property.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001009 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1010 __ add(r6, r6, r5); // Index from start of object.
1011 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1012 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001013 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1014 1, r2, r3);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001015 __ Ret();
1016
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001017 // Load property array property.
1018 __ bind(&property_array_property);
1019 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1020 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1021 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001022 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1023 1, r2, r3);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001024 __ Ret();
1025
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001026 // Do a quick inline probe of the receiver's dictionary, if it
1027 // exists.
1028 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001029 // r1: receiver
1030 // r0: key
1031 // r3: elements
1032 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1033 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1034 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001035 // Load the property to r0.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001036 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001037 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1038 1, r2, r3);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001039 __ Ret();
1040
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001041 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001042 __ IndexFromHash(r3, key);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001043 // Now jump to the place where smi keys are handled.
1044 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045}
1046
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001047
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001048void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1049 // ---------- S t a t e --------------
1050 // -- lr : return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001051 // -- r0 : key (index)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001052 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001053 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001054 Label miss;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001055
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001056 Register receiver = r1;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001057 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001058 Register scratch1 = r2;
1059 Register scratch2 = r3;
1060 Register result = r0;
ager@chromium.org357bf652010-04-12 11:30:10 +00001061
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001062 StringCharAtGenerator char_at_generator(receiver,
1063 index,
1064 scratch1,
1065 scratch2,
1066 result,
1067 &miss, // When not a string.
1068 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001069 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001070 STRING_INDEX_IS_ARRAY_INDEX);
1071 char_at_generator.GenerateFast(masm);
1072 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +00001073
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001074 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001075 char_at_generator.GenerateSlow(masm, call_helper);
ager@chromium.org357bf652010-04-12 11:30:10 +00001076
ager@chromium.org357bf652010-04-12 11:30:10 +00001077 __ bind(&miss);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001078 GenerateMiss(masm, false);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001079}
1080
1081
ager@chromium.org5c838252010-02-19 08:53:10 +00001082void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1083 // ---------- S t a t e --------------
1084 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001085 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001086 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001087 // -----------------------------------
1088 Label slow;
1089
ager@chromium.org5c838252010-02-19 08:53:10 +00001090 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001091 __ JumpIfSmi(r1, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001092
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001093 // Check that the key is an array index, that is Uint32.
1094 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1095 __ b(ne, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001096
1097 // Get the map of the receiver.
1098 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1099
1100 // Check that it has indexed interceptor and access checks
1101 // are not enabled for this object.
1102 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1103 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1104 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1105 __ b(ne, &slow);
1106
1107 // Everything is fine, call runtime.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001108 __ Push(r1, r0); // Receiver, key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001109
1110 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 __ TailCallExternalReference(
1112 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
1113 masm->isolate()),
1114 2,
1115 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001116
1117 __ bind(&slow);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001118 GenerateMiss(masm, false);
ager@chromium.org5c838252010-02-19 08:53:10 +00001119}
1120
1121
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001122void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001123 // ---------- S t a t e --------------
1124 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001125 // -- r1 : key
1126 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001127 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001128 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001129
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001130 // Push receiver, key and value for runtime call.
1131 __ Push(r2, r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001132
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001133 ExternalReference ref = force_generic
1134 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1135 masm->isolate())
1136 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1137 __ TailCallExternalReference(ref, 3, 1);
1138}
1139
1140
1141void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1142 // ---------- S t a t e --------------
1143 // -- r0 : value
1144 // -- r1 : key
1145 // -- r2 : receiver
1146 // -- lr : return address
1147 // -----------------------------------
1148
1149 // Push receiver, key and value for runtime call.
1150 __ Push(r2, r1, r0);
1151
1152 // The slow case calls into the runtime to complete the store without causing
1153 // an IC miss that would otherwise cause a transition to the generic stub.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001154 ExternalReference ref =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001155 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001156 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001157}
1158
1159
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001160void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1161 StrictModeFlag strict_mode) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001162 // ---------- S t a t e --------------
1163 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001164 // -- r1 : key
1165 // -- r2 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001166 // -- lr : return address
ager@chromium.org5c838252010-02-19 08:53:10 +00001167 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001168
1169 // Push receiver, key and value for runtime call.
1170 __ Push(r2, r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001171
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001172 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1173 __ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1174 __ Push(r1, r0);
1175
1176 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177}
1178
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001179
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001180void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1181 StrictModeFlag strict_mode) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001182 // ---------- S t a t e --------------
1183 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001184 // -- r1 : key
1185 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001186 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001187 // -----------------------------------
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001188 Label slow, fast, array, extra;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001189
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001190 // Register usage.
1191 Register value = r0;
1192 Register key = r1;
1193 Register receiver = r2;
1194 Register elements = r3; // Elements array of the receiver.
1195 // r4 and r5 are used as general scratch registers.
1196
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001197 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001198 __ tst(key, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001199 __ b(ne, &slow);
1200 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001201 __ tst(receiver, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001202 __ b(eq, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001203 // Get the map of the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001204 __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001205 // Check that the receiver does not require access checks. We need
1206 // to do this because this generic stub does not perform map checks.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001207 __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001208 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1209 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001210 // Check if the object is a JS array or not.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001211 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
1212 __ cmp(r4, Operand(JS_ARRAY_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001213 __ b(eq, &array);
1214 // Check that the object is some kind of JS object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001215 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001216 __ b(lt, &slow);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001217
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001218 // Object case: Check key against length in the elements array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001219 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001220 // Check that the object is in fast mode and writable.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001221 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001222 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001223 __ cmp(r4, ip);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001224 __ b(ne, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001225 // Check array bounds. Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001226 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001227 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001228 __ b(lo, &fast);
1229
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001230 // Slow case, handle jump to runtime.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001231 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001232 // Entry registers are intact.
1233 // r0: value.
1234 // r1: key.
1235 // r2: receiver.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001236 GenerateRuntimeSetProperty(masm, strict_mode);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001237
1238 // Extra capacity case: Check if there is extra capacity to
1239 // perform the store and update the length. Used for adding one
1240 // element to the array by writing to array[array.length].
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001241 __ bind(&extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001242 // Condition code from comparing key and array length is still available.
1243 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1244 // Check for room in the elements backing store.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001245 // Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001246 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001247 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001248 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001249 // Calculate key + 1 as smi.
1250 ASSERT_EQ(0, kSmiTag);
1251 __ add(r4, key, Operand(Smi::FromInt(1)));
1252 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001253 __ b(&fast);
1254
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001255 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001256 // array. Check that the array is in fast mode (and writable); if it
1257 // is the length is always a smi.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001258 __ bind(&array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001259 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1260 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001261 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001262 __ cmp(r4, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001263 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001264
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001265 // Check the key against the length in the array.
1266 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1267 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001268 __ b(hs, &extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001269 // Fall through to fast case.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001270
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001271 __ bind(&fast);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001272 // Fast case, store the value to the elements backing store.
1273 __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1274 __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1275 __ str(value, MemOperand(r5));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001276 // Skip write barrier if the written value is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001277 __ tst(value, Operand(kSmiTagMask));
1278 __ Ret(eq);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001279 // Update write barrier for the elements array address.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001280 __ sub(r4, r5, Operand(elements));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001281 __ RecordWrite(elements, Operand(r4), r5, r6);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001282
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001283 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284}
1285
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001286
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001287void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001288 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 // ----------- S t a t e -------------
1290 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001291 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292 // -- r2 : name
1293 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // -----------------------------------
1295
1296 // Get the receiver from the stack and probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001297 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1298 NOT_IN_LOOP,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001299 MONOMORPHIC,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001300 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301
1302 Isolate::Current()->stub_cache()->GenerateProbe(
1303 masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304
1305 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001306 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307}
1308
1309
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001310void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001311 // ----------- S t a t e -------------
1312 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001313 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // -- r2 : name
1315 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 // -----------------------------------
1317
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001318 __ Push(r1, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
mads.s.ager31e71382008-08-13 09:32:07 +00001320 // Perform tail call to the entry.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001321 ExternalReference ref =
1322 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001323 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324}
1325
1326
ager@chromium.org5c838252010-02-19 08:53:10 +00001327void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1328 // ----------- S t a t e -------------
1329 // -- r0 : value
1330 // -- r1 : receiver
1331 // -- r2 : name
1332 // -- lr : return address
1333 // -----------------------------------
1334 //
1335 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1336 // (currently anything except for external and pixel arrays which means
1337 // anything with elements of FixedArray type.), but currently is restricted
1338 // to JSArray.
1339 // Value must be a number, but only smis are accepted as the most common case.
1340
1341 Label miss;
1342
1343 Register receiver = r1;
1344 Register value = r0;
1345 Register scratch = r3;
1346
1347 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001348 __ JumpIfSmi(receiver, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001349
1350 // Check that the object is a JS array.
1351 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1352 __ b(ne, &miss);
1353
1354 // Check that elements are FixedArray.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001355 // We rely on StoreIC_ArrayLength below to deal with all types of
1356 // fast elements (including COW).
ager@chromium.org5c838252010-02-19 08:53:10 +00001357 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1358 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1359 __ b(ne, &miss);
1360
1361 // Check that value is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001362 __ JumpIfNotSmi(value, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001363
1364 // Prepare tail call to StoreIC_ArrayLength.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001365 __ Push(receiver, value);
ager@chromium.org5c838252010-02-19 08:53:10 +00001366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001367 ExternalReference ref =
1368 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001369 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001370
1371 __ bind(&miss);
1372
1373 GenerateMiss(masm);
1374}
1375
1376
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001377void StoreIC::GenerateNormal(MacroAssembler* masm) {
1378 // ----------- S t a t e -------------
1379 // -- r0 : value
1380 // -- r1 : receiver
1381 // -- r2 : name
1382 // -- lr : return address
1383 // -----------------------------------
1384 Label miss;
1385
1386 GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1387
1388 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001389 Counters* counters = masm->isolate()->counters();
1390 __ IncrementCounter(counters->store_normal_hit(),
1391 1, r4, r5);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001392 __ Ret();
1393
1394 __ bind(&miss);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001395 __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001396 GenerateMiss(masm);
1397}
1398
1399
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001400void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1401 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001402 // ----------- S t a t e -------------
1403 // -- r0 : value
1404 // -- r1 : receiver
1405 // -- r2 : name
1406 // -- lr : return address
1407 // -----------------------------------
1408
1409 __ Push(r1, r2, r0);
1410
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001411 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1412 __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1413 __ Push(r1, r0);
1414
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001415 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001416 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001417}
1418
1419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420#undef __
1421
1422
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001423Condition CompareIC::ComputeCondition(Token::Value op) {
1424 switch (op) {
1425 case Token::EQ_STRICT:
1426 case Token::EQ:
1427 return eq;
1428 case Token::LT:
1429 return lt;
1430 case Token::GT:
1431 // Reverse left and right operands to obtain ECMA-262 conversion order.
1432 return lt;
1433 case Token::LTE:
1434 // Reverse left and right operands to obtain ECMA-262 conversion order.
1435 return ge;
1436 case Token::GTE:
1437 return ge;
1438 default:
1439 UNREACHABLE();
ager@chromium.org378b34e2011-01-28 08:04:38 +00001440 return kNoCondition;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001441 }
1442}
1443
1444
1445void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1446 HandleScope scope;
1447 Handle<Code> rewritten;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001448 State previous_state = GetState();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001449 State state = TargetState(previous_state, false, x, y);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001450 if (state == GENERIC) {
1451 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1452 rewritten = stub.GetCode();
1453 } else {
1454 ICCompareStub stub(op_, state);
1455 rewritten = stub.GetCode();
1456 }
1457 set_target(*rewritten);
1458
1459#ifdef DEBUG
1460 if (FLAG_trace_ic) {
1461 PrintF("[CompareIC (%s->%s)#%s]\n",
1462 GetStateName(previous_state),
1463 GetStateName(state),
1464 Token::Name(op_));
1465 }
1466#endif
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001467
1468 // Activate inlined smi code.
1469 if (previous_state == UNINITIALIZED) {
1470 PatchInlinedSmiCode(address());
1471 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001472}
1473
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001474
1475void PatchInlinedSmiCode(Address address) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001476 Address cmp_instruction_address =
1477 address + Assembler::kCallTargetAddressOffset;
1478
1479 // If the instruction following the call is not a cmp rx, #yyy, nothing
1480 // was inlined.
1481 Instr instr = Assembler::instr_at(cmp_instruction_address);
1482 if (!Assembler::IsCmpImmediate(instr)) {
1483 return;
1484 }
1485
1486 // The delta to the start of the map check instruction and the
1487 // condition code uses at the patched jump.
1488 int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1489 delta +=
1490 Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1491 // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1492 // nothing was inlined.
1493 if (delta == 0) {
1494 return;
1495 }
1496
1497#ifdef DEBUG
1498 if (FLAG_trace_ic) {
1499 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
1500 address, cmp_instruction_address, delta);
1501 }
1502#endif
1503
1504 Address patch_address =
1505 cmp_instruction_address - delta * Instruction::kInstrSize;
1506 Instr instr_at_patch = Assembler::instr_at(patch_address);
1507 Instr branch_instr =
1508 Assembler::instr_at(patch_address + Instruction::kInstrSize);
1509 ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1510 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1511 Assembler::GetRm(instr_at_patch).code());
1512 ASSERT(Assembler::IsBranch(branch_instr));
1513 if (Assembler::GetCondition(branch_instr) == eq) {
1514 // This is patching a "jump if not smi" site to be active.
1515 // Changing
1516 // cmp rx, rx
1517 // b eq, <target>
1518 // to
1519 // tst rx, #kSmiTagMask
1520 // b ne, <target>
1521 CodePatcher patcher(patch_address, 2);
1522 Register reg = Assembler::GetRn(instr_at_patch);
1523 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1524 patcher.EmitCondition(ne);
1525 } else {
1526 ASSERT(Assembler::GetCondition(branch_instr) == ne);
1527 // This is patching a "jump if smi" site to be active.
1528 // Changing
1529 // cmp rx, rx
1530 // b ne, <target>
1531 // to
1532 // tst rx, #kSmiTagMask
1533 // b eq, <target>
1534 CodePatcher patcher(patch_address, 2);
1535 Register reg = Assembler::GetRn(instr_at_patch);
1536 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1537 patcher.EmitCondition(eq);
1538 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001539}
1540
1541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001543
1544#endif // V8_TARGET_ARCH_ARM