blob: d74468c945473240a2d21ff4b28366615c2ca938 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "codegen-inl.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// Probe the string dictionary in the |elements| register. Jump to the
109// |done| label if a property with the given name is found. Jump to
110// the |miss| label otherwise.
111static void GenerateStringDictionaryProbes(MacroAssembler* masm,
112 Label* miss,
113 Label* done,
114 Register elements,
115 Register name,
116 Register scratch1,
117 Register scratch2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118 // Compute the capacity mask.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000119 const int kCapacityOffset = StringDictionary::kHeaderSize +
120 StringDictionary::kCapacityIndex * kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000121 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
122 __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int
123 __ sub(scratch1, scratch1, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000125 const int kElementsStartOffset = StringDictionary::kHeaderSize +
126 StringDictionary::kElementsStartIndex * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127
128 // Generate an unrolled loop that performs a few probes before
129 // giving up. Measurements done on Gmail indicate that 2 probes
130 // cover ~93% of loads from dictionaries.
131 static const int kProbes = 4;
132 for (int i = 0; i < kProbes; i++) {
133 // Compute the masked index: (hash + i + i * i) & mask.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000134 __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000135 if (i > 0) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000136 // Add the probe offset (i + i * i) left shifted to avoid right shifting
137 // the hash in a separate instruction. The value hash + i + i * i is right
138 // shifted in the following and instruction.
139 ASSERT(StringDictionary::GetProbeOffset(i) <
140 1 << (32 - String::kHashFieldOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000141 __ add(scratch2, scratch2, Operand(
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000142 StringDictionary::GetProbeOffset(i) << String::kHashShift));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000143 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000144 __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145
146 // Scale the index by multiplying by the element size.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000147 ASSERT(StringDictionary::kEntrySize == 3);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000148 // scratch2 = scratch2 * 3.
149 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150
151 // Check if the key is identical to the name.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000152 __ add(scratch2, elements, Operand(scratch2, LSL, 2));
153 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000154 __ cmp(name, Operand(ip));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 if (i != kProbes - 1) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000156 __ b(eq, done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000157 } else {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000158 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 }
160 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000161}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000163
164// Helper function used from LoadIC/CallIC GenerateNormal.
165//
166// elements: Property dictionary. It is not clobbered if a jump to the miss
167// label is done.
168// name: Property name. It is not clobbered if a jump to the miss label is
169// done
170// result: Register for the result. It is only updated if a jump to the miss
171// label is not done. Can be the same as elements or name clobbering
172// one of these in the case of not jumping to the miss label.
173// The two scratch registers need to be different from elements, name and
174// result.
175// The generated code assumes that the receiver has slow properties,
176// is not a global object and does not have interceptors.
177static void GenerateDictionaryLoad(MacroAssembler* masm,
178 Label* miss,
179 Register elements,
180 Register name,
181 Register result,
182 Register scratch1,
183 Register scratch2) {
184 // Main use of the scratch registers.
185 // scratch1: Used as temporary and to hold the capacity of the property
186 // dictionary.
187 // scratch2: Used as temporary.
188 Label done;
189
190 // Probe the dictionary.
191 GenerateStringDictionaryProbes(masm,
192 miss,
193 &done,
194 elements,
195 name,
196 scratch1,
197 scratch2);
198
199 // If probing finds an entry check that the value is a normal
200 // property.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000201 __ bind(&done); // scratch2 == elements + 4 * index
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000202 const int kElementsStartOffset = StringDictionary::kHeaderSize +
203 StringDictionary::kElementsStartIndex * kPointerSize;
204 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
205 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000206 __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000207 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000208
209 // Get the value at the masked, scaled index and return.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000210 __ ldr(result,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000211 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212}
213
214
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000215// Helper function used from StoreIC::GenerateNormal.
216//
217// elements: Property dictionary. It is not clobbered if a jump to the miss
218// label is done.
219// name: Property name. It is not clobbered if a jump to the miss label is
220// done
221// value: The value to store.
222// The two scratch registers need to be different from elements, name and
223// result.
224// The generated code assumes that the receiver has slow properties,
225// is not a global object and does not have interceptors.
226static void GenerateDictionaryStore(MacroAssembler* masm,
227 Label* miss,
228 Register elements,
229 Register name,
230 Register value,
231 Register scratch1,
232 Register scratch2) {
233 // Main use of the scratch registers.
234 // scratch1: Used as temporary and to hold the capacity of the property
235 // dictionary.
236 // scratch2: Used as temporary.
237 Label done;
238
239 // Probe the dictionary.
240 GenerateStringDictionaryProbes(masm,
241 miss,
242 &done,
243 elements,
244 name,
245 scratch1,
246 scratch2);
247
248 // If probing finds an entry in the dictionary check that the value
249 // is a normal property that is not read only.
250 __ bind(&done); // scratch2 == elements + 4 * index
251 const int kElementsStartOffset = StringDictionary::kHeaderSize +
252 StringDictionary::kElementsStartIndex * kPointerSize;
253 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
254 const int kTypeAndReadOnlyMask
255 = (PropertyDetails::TypeField::mask() |
256 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
257 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
258 __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
259 __ b(ne, miss);
260
261 // Store the value at the masked, scaled index and return.
262 const int kValueOffset = kElementsStartOffset + kPointerSize;
263 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
264 __ str(value, MemOperand(scratch2));
265
266 // Update the write barrier. Make sure not to clobber the value.
267 __ mov(scratch1, value);
268 __ RecordWrite(elements, scratch2, scratch1);
269}
270
271
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000272static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
273 Label* miss,
274 Register elements,
275 Register key,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000276 Register result,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000277 Register t0,
278 Register t1,
279 Register t2) {
280 // Register use:
281 //
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000282 // elements - holds the slow-case elements of the receiver on entry.
283 // Unchanged unless 'result' is the same register.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000284 //
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000285 // key - holds the smi key on entry.
286 // Unchanged unless 'result' is the same register.
287 //
288 // result - holds the result on exit if the load succeeded.
289 // Allowed to be the same as 'key' or 'result'.
290 // Unchanged on bailout so 'key' or 'result' can be used
291 // in further computation.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000292 //
293 // Scratch registers:
294 //
295 // t0 - holds the untagged key on entry and holds the hash once computed.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000296 //
297 // t1 - used to hold the capacity mask of the dictionary
298 //
299 // t2 - used for the index into the dictionary.
300 Label done;
301
302 // Compute the hash code from the untagged key. This must be kept in sync
303 // with ComputeIntegerHash in utils.h.
304 //
305 // hash = ~hash + (hash << 15);
306 __ mvn(t1, Operand(t0));
307 __ add(t0, t1, Operand(t0, LSL, 15));
308 // hash = hash ^ (hash >> 12);
309 __ eor(t0, t0, Operand(t0, LSR, 12));
310 // hash = hash + (hash << 2);
311 __ add(t0, t0, Operand(t0, LSL, 2));
312 // hash = hash ^ (hash >> 4);
313 __ eor(t0, t0, Operand(t0, LSR, 4));
314 // hash = hash * 2057;
315 __ mov(t1, Operand(2057));
316 __ mul(t0, t0, t1);
317 // hash = hash ^ (hash >> 16);
318 __ eor(t0, t0, Operand(t0, LSR, 16));
319
320 // Compute the capacity mask.
321 __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
322 __ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
323 __ sub(t1, t1, Operand(1));
324
325 // Generate an unrolled loop that performs a few probes before giving up.
326 static const int kProbes = 4;
327 for (int i = 0; i < kProbes; i++) {
328 // Use t2 for index calculations and keep the hash intact in t0.
329 __ mov(t2, t0);
330 // Compute the masked index: (hash + i + i * i) & mask.
331 if (i > 0) {
332 __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
333 }
334 __ and_(t2, t2, Operand(t1));
335
336 // Scale the index by multiplying by the element size.
337 ASSERT(NumberDictionary::kEntrySize == 3);
338 __ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
339
340 // Check if the key is identical to the name.
341 __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
342 __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
343 __ cmp(key, Operand(ip));
344 if (i != kProbes - 1) {
345 __ b(eq, &done);
346 } else {
347 __ b(ne, miss);
348 }
349 }
350
351 __ bind(&done);
352 // Check that the value is a normal property.
353 // t2: elements + (index * kPointerSize)
354 const int kDetailsOffset =
355 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
356 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
357 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
358 __ b(ne, miss);
359
360 // Get the value at the masked, scaled index and return.
361 const int kValueOffset =
362 NumberDictionary::kElementsStartOffset + kPointerSize;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000363 __ ldr(result, FieldMemOperand(t2, kValueOffset));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000364}
365
366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000367void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
368 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 // -- r2 : name
370 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000371 // -- r0 : receiver
372 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000373 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000374 Label miss;
375
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000376 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000378 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000379}
380
381
ager@chromium.org378b34e2011-01-28 08:04:38 +0000382void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 // -- r2 : name
385 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000386 // -- r0 : receiver
387 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000389 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000390
ager@chromium.org378b34e2011-01-28 08:04:38 +0000391 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
392 support_wrappers);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393 // Cache miss: Jump to runtime.
394 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000395 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396}
397
398
399void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
400 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 // -- r2 : name
402 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000403 // -- r0 : receiver
404 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 // -----------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000406 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000407
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000408 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
409 __ bind(&miss);
410 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411}
412
413
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000414// Checks the receiver for special cases (value type, slow case bits).
415// Falls through for regular JS object.
416static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
417 Register receiver,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000418 Register map,
419 Register scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000420 int interceptor_bit,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000421 Label* slow) {
422 // Check that the object isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000423 __ JumpIfSmi(receiver, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000424 // Get the map of the receiver.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000425 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000426 // Check bit field.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000427 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
428 __ tst(scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000429 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000430 __ b(ne, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000431 // Check that the object is some kind of JS object EXCEPT JS Value type.
432 // In the case that the object is a value-wrapper object,
433 // we enter the runtime system to make sure that indexing into string
434 // objects work as intended.
435 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000436 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
437 __ cmp(scratch, Operand(JS_OBJECT_TYPE));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000438 __ b(lt, slow);
439}
440
441
442// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000443// If not_fast_array is NULL, doesn't perform the elements map check.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000444static void GenerateFastArrayLoad(MacroAssembler* masm,
445 Register receiver,
446 Register key,
447 Register elements,
448 Register scratch1,
449 Register scratch2,
450 Register result,
451 Label* not_fast_array,
452 Label* out_of_range) {
453 // Register use:
454 //
455 // receiver - holds the receiver on entry.
456 // Unchanged unless 'result' is the same register.
457 //
458 // key - holds the smi key on entry.
459 // Unchanged unless 'result' is the same register.
460 //
461 // elements - holds the elements of the receiver on exit.
462 //
463 // result - holds the result on exit if the load succeeded.
464 // Allowed to be the the same as 'receiver' or 'key'.
465 // Unchanged on bailout so 'receiver' and 'key' can be safely
466 // used by further computation.
467 //
468 // Scratch registers:
469 //
470 // scratch1 - used to hold elements map and elements length.
471 // Holds the elements map if not_fast_array branch is taken.
472 //
473 // scratch2 - used to hold the loaded value.
474
475 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000476 if (not_fast_array != NULL) {
477 // Check that the object is in fast mode and writable.
478 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
479 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
480 __ cmp(scratch1, ip);
481 __ b(ne, not_fast_array);
482 } else {
483 __ AssertFastElements(elements);
484 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000485 // Check that the key (index) is within bounds.
486 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
487 __ cmp(key, Operand(scratch1));
488 __ b(hs, out_of_range);
489 // Fast case: Do the load.
490 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
491 // The key is a smi.
492 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
493 __ ldr(scratch2,
494 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
495 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
496 __ cmp(scratch2, ip);
497 // In case the loaded value is the_hole we have to consult GetProperty
498 // to ensure the prototype chain is searched.
499 __ b(eq, out_of_range);
500 __ mov(result, scratch2);
501}
502
503
504// Checks whether a key is an array index string or a symbol string.
505// Falls through if a key is a symbol.
506static void GenerateKeyStringCheck(MacroAssembler* masm,
507 Register key,
508 Register map,
509 Register hash,
510 Label* index_string,
511 Label* not_symbol) {
512 // The key is not a smi.
513 // Is it a string?
514 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
515 __ b(ge, not_symbol);
516
517 // Is the string an array index, with cached numeric value?
518 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
519 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
520 __ b(eq, index_string);
521
522 // Is the string a symbol?
523 // map: key map
524 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
525 ASSERT(kSymbolTag != 0);
526 __ tst(hash, Operand(kIsSymbolMask));
527 __ b(eq, not_symbol);
528}
529
530
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531// Defined in ic.cc.
532Object* CallIC_Miss(Arguments args);
533
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000534// The generated code does not accept smi keys.
535// The generated code falls through if both probes miss.
536static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
537 int argc,
538 Code::Kind kind) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 // ----------- S t a t e -------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000540 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000541 // -- r2 : name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 // -----------------------------------
543 Label number, non_number, non_string, boolean, probe, miss;
544
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000546 Code::Flags flags = Code::ComputeFlags(kind,
547 NOT_IN_LOOP,
548 MONOMORPHIC,
549 Code::kNoExtraICState,
550 NORMAL,
551 argc);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000552 StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553
554 // If the stub cache probing failed, the receiver might be a value.
555 // For value objects, we use the map of the prototype objects for
556 // the corresponding JSValue for the cache and that is what we need
557 // to probe.
558 //
559 // Check for number.
560 __ tst(r1, Operand(kSmiTagMask));
561 __ b(eq, &number);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000562 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 __ b(ne, &non_number);
564 __ bind(&number);
565 StubCompiler::GenerateLoadGlobalFunctionPrototype(
566 masm, Context::NUMBER_FUNCTION_INDEX, r1);
567 __ b(&probe);
568
569 // Check for string.
570 __ bind(&non_number);
571 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
572 __ b(hs, &non_string);
573 StubCompiler::GenerateLoadGlobalFunctionPrototype(
574 masm, Context::STRING_FUNCTION_INDEX, r1);
575 __ b(&probe);
576
577 // Check for boolean.
578 __ bind(&non_string);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000579 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
580 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000581 __ b(eq, &boolean);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000582 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
583 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584 __ b(ne, &miss);
585 __ bind(&boolean);
586 StubCompiler::GenerateLoadGlobalFunctionPrototype(
587 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
588
589 // Probe the stub cache for the value object.
590 __ bind(&probe);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000591 StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000592
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594}
595
596
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000597static void GenerateFunctionTailCall(MacroAssembler* masm,
598 int argc,
599 Label* miss,
600 Register scratch) {
601 // r1: function
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000602
603 // Check that the value isn't a smi.
604 __ tst(r1, Operand(kSmiTagMask));
605 __ b(eq, miss);
606
607 // Check that the value is a JSFunction.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000608 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000609 __ b(ne, miss);
610
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000611 // Invoke the function.
612 ParameterCount actual(argc);
613 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
614}
615
616
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000617static void GenerateCallNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000619 // -- r2 : name
620 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000622 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623
mads.s.ager31e71382008-08-13 09:32:07 +0000624 // Get the receiver of the function from the stack into r1.
625 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000627 GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000628
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000629 // r0: elements
630 // Search the dictionary - put result in register r1.
631 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000633 GenerateFunctionTailCall(masm, argc, &miss, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636}
637
638
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000639static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000641 // -- r2 : name
642 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 // -----------------------------------
644
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000645 if (id == IC::kCallIC_Miss) {
646 __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
647 } else {
648 __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
649 }
650
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000651 // Get the receiver of the function from the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +0000652 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000653
654 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655
656 // Push the receiver and the name of the function.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000657 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658
659 // Call the entry.
mads.s.ager31e71382008-08-13 09:32:07 +0000660 __ mov(r0, Operand(2));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000661 __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662
ager@chromium.orga1645e22009-09-09 19:27:10 +0000663 CEntryStub stub(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664 __ CallStub(&stub);
665
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000666 // Move result to r1 and leave the internal frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667 __ mov(r1, Operand(r0));
ager@chromium.org236ad962008-09-25 09:45:57 +0000668 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000669
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000670 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000671 // This can happen only for regular CallIC but not KeyedCallIC.
672 if (id == IC::kCallIC_Miss) {
673 Label invoke, global;
674 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
675 __ tst(r2, Operand(kSmiTagMask));
676 __ b(eq, &invoke);
677 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
678 __ b(eq, &global);
679 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
680 __ b(ne, &invoke);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000681
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000682 // Patch the receiver on the stack.
683 __ bind(&global);
684 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
685 __ str(r2, MemOperand(sp, argc * kPointerSize));
686 __ bind(&invoke);
687 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000688
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000689 // Invoke the function.
690 ParameterCount actual(argc);
691 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692}
693
694
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000695void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
696 // ----------- S t a t e -------------
697 // -- r2 : name
698 // -- lr : return address
699 // -----------------------------------
700
701 GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
702}
703
704
705void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
706 // ----------- S t a t e -------------
707 // -- r2 : name
708 // -- lr : return address
709 // -----------------------------------
710
711 // Get the receiver of the function from the stack into r1.
712 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
713 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
714 GenerateMiss(masm, argc);
715}
716
717
718void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
719 // ----------- S t a t e -------------
720 // -- r2 : name
721 // -- lr : return address
722 // -----------------------------------
723
724 GenerateCallNormal(masm, argc);
725 GenerateMiss(masm, argc);
726}
727
728
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000729void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000730 // ----------- S t a t e -------------
731 // -- r2 : name
732 // -- lr : return address
733 // -----------------------------------
734
735 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000736}
737
738
739void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000740 // ----------- S t a t e -------------
741 // -- r2 : name
742 // -- lr : return address
743 // -----------------------------------
744
745 // Get the receiver of the function from the stack into r1.
746 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
747
748 Label do_call, slow_call, slow_load, slow_reload_receiver;
749 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
750 Label index_smi, index_string;
751
752 // Check that the key is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000753 __ JumpIfNotSmi(r2, &check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000754 __ bind(&index_smi);
755 // Now the key is known to be a smi. This place is also jumped to from below
756 // where a numeric string is converted to a smi.
757
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000758 GenerateKeyedLoadReceiverCheck(
759 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000760
761 GenerateFastArrayLoad(
762 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
763 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
764
765 __ bind(&do_call);
766 // receiver in r1 is not used after this point.
767 // r2: key
768 // r1: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000769 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000770
771 __ bind(&check_number_dictionary);
772 // r2: key
773 // r3: elements map
774 // r4: elements
775 // Check whether the elements is a number dictionary.
776 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
777 __ cmp(r3, ip);
778 __ b(ne, &slow_load);
779 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
780 // r0: untagged index
781 GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
782 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
783 __ jmp(&do_call);
784
785 __ bind(&slow_load);
786 // This branch is taken when calling KeyedCallIC_Miss is neither required
787 // nor beneficial.
788 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
789 __ EnterInternalFrame();
790 __ push(r2); // save the key
791 __ Push(r1, r2); // pass the receiver and the key
792 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
793 __ pop(r2); // restore the key
794 __ LeaveInternalFrame();
795 __ mov(r1, r0);
796 __ jmp(&do_call);
797
798 __ bind(&check_string);
799 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
800
801 // The key is known to be a symbol.
802 // If the receiver is a regular JS object with slow properties then do
803 // a quick inline probe of the receiver's dictionary.
804 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000805 GenerateKeyedLoadReceiverCheck(
806 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000807
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000808 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
809 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000810 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
811 __ cmp(r3, ip);
812 __ b(ne, &lookup_monomorphic_cache);
813
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000814 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000815 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
816 __ jmp(&do_call);
817
818 __ bind(&lookup_monomorphic_cache);
819 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
820 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
821 // Fall through on miss.
822
823 __ bind(&slow_call);
824 // This branch is taken if:
825 // - the receiver requires boxing or access check,
826 // - the key is neither smi nor symbol,
827 // - the value loaded is not a function,
828 // - there is hope that the runtime will create a monomorphic call stub
829 // that will get fetched next time.
830 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
831 GenerateMiss(masm, argc);
832
833 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000834 __ IndexFromHash(r3, r2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000835 // Now jump to the place where smi keys are handled.
836 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000837}
838
839
840void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000841 // ----------- S t a t e -------------
842 // -- r2 : name
843 // -- lr : return address
844 // -----------------------------------
845
846 GenerateCallNormal(masm, argc);
847 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000848}
849
850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851// Defined in ic.cc.
852Object* LoadIC_Miss(Arguments args);
853
854void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
855 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 // -- r2 : name
857 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000858 // -- r0 : receiver
859 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 // -----------------------------------
861
862 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000863 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
864 NOT_IN_LOOP,
865 MONOMORPHIC);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000866 StubCache::GenerateProbe(masm, flags, r0, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867
868 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +0000869 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870}
871
872
873void LoadIC::GenerateNormal(MacroAssembler* masm) {
874 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000875 // -- r2 : name
876 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000877 // -- r0 : receiver
878 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000879 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000880 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000882 GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000884 // r1: elements
885 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 __ Ret();
887
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000888 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000890 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891}
892
893
894void LoadIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 // -- r2 : name
897 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000898 // -- r0 : receiver
899 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 // -----------------------------------
901
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000902 __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
903
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000904 __ mov(r3, r0);
905 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906
mads.s.ager31e71382008-08-13 09:32:07 +0000907 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000908 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
909 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910}
911
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000912// Returns the code marker, or the 0 if the code is not marked.
913static inline int InlinedICSiteMarker(Address address,
914 Address* inline_end_address) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000915 if (V8::UseCrankshaft()) return false;
916
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000917 // If the instruction after the call site is not the pseudo instruction nop1
918 // then this is not related to an inlined in-object property load. The nop1
919 // instruction is located just after the call to the IC in the deferred code
920 // handling the miss in the inlined code. After the nop1 instruction there is
921 // a branch instruction for jumping back from the deferred code.
922 Address address_after_call = address + Assembler::kCallTargetAddressOffset;
923 Instr instr_after_call = Assembler::instr_at(address_after_call);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000924 int code_marker = MacroAssembler::GetCodeMarker(instr_after_call);
925
926 // A negative result means the code is not marked.
927 if (code_marker <= 0) return 0;
928
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000929 Address address_after_nop = address_after_call + Assembler::kInstrSize;
930 Instr instr_after_nop = Assembler::instr_at(address_after_nop);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000931 // There may be some reg-reg move and frame merging code to skip over before
932 // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
933 // code.
934 while (!Assembler::IsBranch(instr_after_nop)) {
935 address_after_nop += Assembler::kInstrSize;
936 instr_after_nop = Assembler::instr_at(address_after_nop);
937 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000938
939 // Find the end of the inlined code for handling the load.
940 int b_offset =
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000941 Assembler::GetBranchOffset(instr_after_nop) + Assembler::kPcLoadDelta;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000942 ASSERT(b_offset < 0); // Jumping back from deferred code.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000943 *inline_end_address = address_after_nop + b_offset;
944
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000945 return code_marker;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000946}
947
948
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000949bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950 if (V8::UseCrankshaft()) return false;
951
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000952 // Find the end of the inlined code for handling the load if this is an
953 // inlined IC call site.
954 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000955 if (InlinedICSiteMarker(address, &inline_end_address)
956 != Assembler::PROPERTY_ACCESS_INLINED) {
957 return false;
958 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000959
960 // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000961 // The immediate must be representable in 12 bits.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000962 ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000963 Address ldr_property_instr_address =
964 inline_end_address - Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000965 ASSERT(Assembler::IsLdrRegisterImmediate(
966 Assembler::instr_at(ldr_property_instr_address)));
967 Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
968 ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
969 ldr_property_instr, offset - kHeapObjectTag);
970 Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
971
972 // Indicate that code has changed.
973 CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
974
975 // Patch the map check.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000976 // For PROPERTY_ACCESS_INLINED, the load map instruction is generated
977 // 4 instructions before the end of the inlined code.
978 // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
979 int ldr_map_offset = -4;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000980 Address ldr_map_instr_address =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000981 inline_end_address + ldr_map_offset * Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000982 Assembler::set_target_address_at(ldr_map_instr_address,
983 reinterpret_cast<Address>(map));
984 return true;
985}
986
987
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000988bool LoadIC::PatchInlinedContextualLoad(Address address,
989 Object* map,
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000990 Object* cell,
991 bool is_dont_delete) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000992 // Find the end of the inlined code for handling the contextual load if
993 // this is inlined IC call site.
994 Address inline_end_address;
995 int marker = InlinedICSiteMarker(address, &inline_end_address);
996 if (!((marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT) ||
997 (marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE))) {
998 return false;
999 }
1000 // On ARM we don't rely on the is_dont_delete argument as the hint is already
1001 // embedded in the code marker.
1002 bool marker_is_dont_delete =
1003 marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE;
1004
1005 // These are the offsets from the end of the inlined code.
1006 // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
1007 int ldr_map_offset = marker_is_dont_delete ? -5: -8;
1008 int ldr_cell_offset = marker_is_dont_delete ? -2: -5;
1009 if (FLAG_debug_code && marker_is_dont_delete) {
1010 // Three extra instructions were generated to check for the_hole_value.
1011 ldr_map_offset -= 3;
1012 ldr_cell_offset -= 3;
1013 }
1014 Address ldr_map_instr_address =
1015 inline_end_address + ldr_map_offset * Assembler::kInstrSize;
1016 Address ldr_cell_instr_address =
1017 inline_end_address + ldr_cell_offset * Assembler::kInstrSize;
1018
1019 // Patch the map check.
1020 Assembler::set_target_address_at(ldr_map_instr_address,
1021 reinterpret_cast<Address>(map));
1022 // Patch the cell address.
1023 Assembler::set_target_address_at(ldr_cell_instr_address,
1024 reinterpret_cast<Address>(cell));
1025
1026 return true;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001027}
1028
1029
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001030bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001031 if (V8::UseCrankshaft()) return false;
1032
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001033 // Find the end of the inlined code for the store if there is an
1034 // inlined version of the store.
1035 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001036 if (InlinedICSiteMarker(address, &inline_end_address)
1037 != Assembler::PROPERTY_ACCESS_INLINED) {
1038 return false;
1039 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001040
1041 // Compute the address of the map load instruction.
1042 Address ldr_map_instr_address =
1043 inline_end_address -
1044 (CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
1045 Assembler::kInstrSize);
1046
1047 // Update the offsets if initializing the inlined store. No reason
1048 // to update the offsets when clearing the inlined version because
1049 // it will bail out in the map check.
1050 if (map != Heap::null_value()) {
1051 // Patch the offset in the actual store instruction.
1052 Address str_property_instr_address =
1053 ldr_map_instr_address + 3 * Assembler::kInstrSize;
1054 Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
1055 ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
1056 str_property_instr = Assembler::SetStrRegisterImmediateOffset(
1057 str_property_instr, offset - kHeapObjectTag);
1058 Assembler::instr_at_put(str_property_instr_address, str_property_instr);
1059
1060 // Patch the offset in the add instruction that is part of the
1061 // write barrier.
1062 Address add_offset_instr_address =
1063 str_property_instr_address + Assembler::kInstrSize;
1064 Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
1065 ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
1066 add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
1067 add_offset_instr, offset - kHeapObjectTag);
1068 Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
1069
1070 // Indicate that code has changed.
1071 CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
1072 }
1073
1074 // Patch the map check.
1075 Assembler::set_target_address_at(ldr_map_instr_address,
1076 reinterpret_cast<Address>(map));
1077
1078 return true;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001079}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001080
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001081
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001082bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001083 if (V8::UseCrankshaft()) return false;
1084
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001085 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001086 if (InlinedICSiteMarker(address, &inline_end_address)
1087 != Assembler::PROPERTY_ACCESS_INLINED) {
1088 return false;
1089 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001090
1091 // Patch the map check.
1092 Address ldr_map_instr_address =
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001093 inline_end_address -
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001094 (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001095 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001096 Assembler::set_target_address_at(ldr_map_instr_address,
1097 reinterpret_cast<Address>(map));
1098 return true;
1099}
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001100
1101
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001102bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001103 if (V8::UseCrankshaft()) return false;
1104
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001105 // Find the end of the inlined code for handling the store if this is an
1106 // inlined IC call site.
1107 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001108 if (InlinedICSiteMarker(address, &inline_end_address)
1109 != Assembler::PROPERTY_ACCESS_INLINED) {
1110 return false;
1111 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001112
1113 // Patch the map check.
1114 Address ldr_map_instr_address =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001115 inline_end_address -
1116 (CodeGenerator::kInlinedKeyedStoreInstructionsAfterPatch *
1117 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001118 Assembler::set_target_address_at(ldr_map_instr_address,
1119 reinterpret_cast<Address>(map));
1120 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001121}
1122
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001123
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001124Object* KeyedLoadIC_Miss(Arguments args);
1125
1126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001127void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001128 // ---------- 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
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001132 // -----------------------------------
1133
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001134 __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
1135
ager@chromium.orgac091b72010-05-05 07:34:42 +00001136 __ Push(r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001137
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001138 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1139 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001140}
1141
1142
1143void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1144 // ---------- S t a t e --------------
1145 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001146 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001147 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001148 // -----------------------------------
1149
ager@chromium.orgac091b72010-05-05 07:34:42 +00001150 __ Push(r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001151
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001152 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153}
1154
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001155
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001157 // ---------- S t a t e --------------
1158 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001159 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001160 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001161 // -----------------------------------
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001162 Label slow, check_string, index_smi, index_string, property_array_property;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001163 Label check_pixel_array, probe_dictionary, check_number_dictionary;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001164
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001165 Register key = r0;
1166 Register receiver = r1;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001167
ager@chromium.org5c838252010-02-19 08:53:10 +00001168 // Check that the key is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001169 __ JumpIfNotSmi(key, &check_string);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001170 __ bind(&index_smi);
1171 // Now the key is known to be a smi. This place is also jumped to from below
1172 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001173
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001174 GenerateKeyedLoadReceiverCheck(
1175 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
1176
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001177 // Check the "has fast elements" bit in the receiver's map which is
1178 // now in r2.
1179 __ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset));
1180 __ tst(r3, Operand(1 << Map::kHasFastElements));
1181 __ b(eq, &check_pixel_array);
1182
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001183 GenerateFastArrayLoad(
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001184 masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001185 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001186 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001187
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001188 // Check whether the elements is a pixel array.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001189 // r0: key
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001190 // r1: receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001191 __ bind(&check_pixel_array);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001192 __ ldr(r4, FieldMemOperand(r1, JSObject::kElementsOffset));
1193 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001194 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
1195 __ cmp(r3, ip);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001196 __ b(ne, &check_number_dictionary);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001197 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001198 __ mov(r2, Operand(key, ASR, kSmiTagSize));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001199 __ cmp(r2, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001200 __ b(hs, &slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001201 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset));
1202 __ ldrb(r2, MemOperand(ip, r2));
1203 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001204 __ Ret();
1205
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001206 __ bind(&check_number_dictionary);
1207 // Check whether the elements is a number dictionary.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001208 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001209 // r3: elements map
1210 // r4: elements
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001211 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1212 __ cmp(r3, ip);
1213 __ b(ne, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001214 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001215 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001216 __ Ret();
1217
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001218 // Slow case, key and receiver still in r0 and r1.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001219 __ bind(&slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001220 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
ager@chromium.org5c838252010-02-19 08:53:10 +00001221 GenerateRuntimeGetProperty(masm);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001222
1223 __ bind(&check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001224 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001225
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001226 GenerateKeyedLoadReceiverCheck(
1227 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1228
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001229 // If the receiver is a fast-case object, check the keyed lookup
1230 // cache. Otherwise probe the dictionary.
1231 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001232 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001233 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001234 __ cmp(r4, ip);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001235 __ b(eq, &probe_dictionary);
1236
1237 // Load the map of the receiver, compute the keyed lookup cache hash
1238 // based on 32 bits of the map pointer and the string hash.
1239 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1240 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1241 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1242 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001243 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001244
1245 // Load the key (consisting of map and symbol) from the cache and
1246 // check for match.
1247 ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
1248 __ mov(r4, Operand(cache_keys));
1249 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1250 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
1251 __ cmp(r2, r5);
1252 __ b(ne, &slow);
1253 __ ldr(r5, MemOperand(r4));
1254 __ cmp(r0, r5);
1255 __ b(ne, &slow);
1256
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001257 // Get field offset.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001258 // r0 : key
1259 // r1 : receiver
1260 // r2 : receiver's map
1261 // r3 : lookup cache index
1262 ExternalReference cache_field_offsets
1263 = ExternalReference::keyed_lookup_cache_field_offsets();
1264 __ mov(r4, Operand(cache_field_offsets));
1265 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1266 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001267 __ sub(r5, r5, r6, SetCC);
1268 __ b(ge, &property_array_property);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001269
1270 // Load in-object property.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001271 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1272 __ add(r6, r6, r5); // Index from start of object.
1273 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1274 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1275 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1276 __ Ret();
1277
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001278 // Load property array property.
1279 __ bind(&property_array_property);
1280 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1281 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1282 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
1283 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1284 __ Ret();
1285
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001286 // Do a quick inline probe of the receiver's dictionary, if it
1287 // exists.
1288 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001289 // r1: receiver
1290 // r0: key
1291 // r3: elements
1292 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1293 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1294 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001295 // Load the property to r0.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001296 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001297 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
1298 __ Ret();
1299
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001300 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001301 __ IndexFromHash(r3, key);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001302 // Now jump to the place where smi keys are handled.
1303 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304}
1305
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001306
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001307void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1308 // ---------- S t a t e --------------
1309 // -- lr : return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001310 // -- r0 : key (index)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001311 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001312 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001313 Label miss;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001314
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001315 Register receiver = r1;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001316 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001317 Register scratch1 = r2;
1318 Register scratch2 = r3;
1319 Register result = r0;
ager@chromium.org357bf652010-04-12 11:30:10 +00001320
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001321 StringCharAtGenerator char_at_generator(receiver,
1322 index,
1323 scratch1,
1324 scratch2,
1325 result,
1326 &miss, // When not a string.
1327 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001328 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001329 STRING_INDEX_IS_ARRAY_INDEX);
1330 char_at_generator.GenerateFast(masm);
1331 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +00001332
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001333 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001334 char_at_generator.GenerateSlow(masm, call_helper);
ager@chromium.org357bf652010-04-12 11:30:10 +00001335
ager@chromium.org357bf652010-04-12 11:30:10 +00001336 __ bind(&miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001337 GenerateMiss(masm);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001338}
1339
1340
ager@chromium.org5c838252010-02-19 08:53:10 +00001341void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1342 // ---------- S t a t e --------------
1343 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001344 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001345 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001346 // -----------------------------------
1347 Label slow;
1348
ager@chromium.org5c838252010-02-19 08:53:10 +00001349 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001350 __ JumpIfSmi(r1, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001351
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001352 // Check that the key is an array index, that is Uint32.
1353 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1354 __ b(ne, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001355
1356 // Get the map of the receiver.
1357 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1358
1359 // Check that it has indexed interceptor and access checks
1360 // are not enabled for this object.
1361 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1362 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1363 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1364 __ b(ne, &slow);
1365
1366 // Everything is fine, call runtime.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001367 __ Push(r1, r0); // Receiver, key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001368
1369 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001370 __ TailCallExternalReference(ExternalReference(
ager@chromium.org5c838252010-02-19 08:53:10 +00001371 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
1372
1373 __ bind(&slow);
1374 GenerateMiss(masm);
1375}
1376
1377
1378void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001379 // ---------- S t a t e --------------
1380 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001381 // -- r1 : key
1382 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001383 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001384 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001385
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001386 // Push receiver, key and value for runtime call.
1387 __ Push(r2, r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001388
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001389 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1390 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001391}
1392
1393
1394void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1395 // ---------- S t a t e --------------
1396 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001397 // -- r1 : key
1398 // -- r2 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001399 // -- lr : return address
ager@chromium.org5c838252010-02-19 08:53:10 +00001400 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001401
1402 // Push receiver, key and value for runtime call.
1403 __ Push(r2, r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001404
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001405 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406}
1407
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
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 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001416 Label slow, fast, array, extra, check_pixel_array;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001417
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001418 // Register usage.
1419 Register value = r0;
1420 Register key = r1;
1421 Register receiver = r2;
1422 Register elements = r3; // Elements array of the receiver.
1423 // r4 and r5 are used as general scratch registers.
1424
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001425 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001426 __ tst(key, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001427 __ b(ne, &slow);
1428 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001429 __ tst(receiver, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001430 __ b(eq, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001431 // Get the map of the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001432 __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001433 // Check that the receiver does not require access checks. We need
1434 // to do this because this generic stub does not perform map checks.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001435 __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001436 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1437 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001438 // Check if the object is a JS array or not.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001439 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
1440 __ cmp(r4, Operand(JS_ARRAY_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001441 __ b(eq, &array);
1442 // Check that the object is some kind of JS object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001443 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001444 __ b(lt, &slow);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001445
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001446 // Object case: Check key against length in the elements array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001447 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001448 // Check that the object is in fast mode and writable.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001449 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001450 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001451 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001452 __ b(ne, &check_pixel_array);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001453 // Check array bounds. Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001454 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001455 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001456 __ b(lo, &fast);
1457
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001458 // Slow case, handle jump to runtime.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001459 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001460 // Entry registers are intact.
1461 // r0: value.
1462 // r1: key.
1463 // r2: receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001464 GenerateRuntimeSetProperty(masm);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001465
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001466 // Check whether the elements is a pixel array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001467 // r4: elements map.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001468 __ bind(&check_pixel_array);
1469 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001470 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001471 __ b(ne, &slow);
1472 // Check that the value is a smi. If a conversion is needed call into the
1473 // runtime to convert and clamp.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001474 __ JumpIfNotSmi(value, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001475 __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the key.
1476 __ ldr(ip, FieldMemOperand(elements, PixelArray::kLengthOffset));
1477 __ cmp(r4, Operand(ip));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001478 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001479 __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001480 __ Usat(r5, 8, Operand(r5)); // Clamp the value to [0..255].
1481
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001482 // Get the pointer to the external array. This clobbers elements.
1483 __ ldr(elements,
1484 FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
1485 __ strb(r5, MemOperand(elements, r4)); // Elements is now external array.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001486 __ Ret();
1487
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001488 // Extra capacity case: Check if there is extra capacity to
1489 // perform the store and update the length. Used for adding one
1490 // element to the array by writing to array[array.length].
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001491 __ bind(&extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001492 // Condition code from comparing key and array length is still available.
1493 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1494 // Check for room in the elements backing store.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001495 // Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001496 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001497 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001498 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001499 // Calculate key + 1 as smi.
1500 ASSERT_EQ(0, kSmiTag);
1501 __ add(r4, key, Operand(Smi::FromInt(1)));
1502 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001503 __ b(&fast);
1504
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001505 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001506 // array. Check that the array is in fast mode (and writable); if it
1507 // is the length is always a smi.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001508 __ bind(&array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001509 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1510 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001511 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001512 __ cmp(r4, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001513 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001514
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001515 // Check the key against the length in the array.
1516 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1517 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001518 __ b(hs, &extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001519 // Fall through to fast case.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001520
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001521 __ bind(&fast);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001522 // Fast case, store the value to the elements backing store.
1523 __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1524 __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1525 __ str(value, MemOperand(r5));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001526 // Skip write barrier if the written value is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001527 __ tst(value, Operand(kSmiTagMask));
1528 __ Ret(eq);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001529 // Update write barrier for the elements array address.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001530 __ sub(r4, r5, Operand(elements));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001531 __ RecordWrite(elements, Operand(r4), r5, r6);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001532
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001533 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534}
1535
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001536
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001537void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1538 // ----------- S t a t e -------------
1539 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001540 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541 // -- r2 : name
1542 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // -----------------------------------
1544
1545 // Get the receiver from the stack and probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001546 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1547 NOT_IN_LOOP,
1548 MONOMORPHIC);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001549 StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550
1551 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001552 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553}
1554
1555
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001556void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557 // ----------- S t a t e -------------
1558 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001559 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 // -- r2 : name
1561 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // -----------------------------------
1563
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001564 __ Push(r1, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565
mads.s.ager31e71382008-08-13 09:32:07 +00001566 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001567 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1568 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569}
1570
1571
ager@chromium.org5c838252010-02-19 08:53:10 +00001572void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1573 // ----------- S t a t e -------------
1574 // -- r0 : value
1575 // -- r1 : receiver
1576 // -- r2 : name
1577 // -- lr : return address
1578 // -----------------------------------
1579 //
1580 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1581 // (currently anything except for external and pixel arrays which means
1582 // anything with elements of FixedArray type.), but currently is restricted
1583 // to JSArray.
1584 // Value must be a number, but only smis are accepted as the most common case.
1585
1586 Label miss;
1587
1588 Register receiver = r1;
1589 Register value = r0;
1590 Register scratch = r3;
1591
1592 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001593 __ JumpIfSmi(receiver, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001594
1595 // Check that the object is a JS array.
1596 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1597 __ b(ne, &miss);
1598
1599 // Check that elements are FixedArray.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001600 // We rely on StoreIC_ArrayLength below to deal with all types of
1601 // fast elements (including COW).
ager@chromium.org5c838252010-02-19 08:53:10 +00001602 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1603 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1604 __ b(ne, &miss);
1605
1606 // Check that value is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001607 __ JumpIfNotSmi(value, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001608
1609 // Prepare tail call to StoreIC_ArrayLength.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001610 __ Push(receiver, value);
ager@chromium.org5c838252010-02-19 08:53:10 +00001611
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001612 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1613 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001614
1615 __ bind(&miss);
1616
1617 GenerateMiss(masm);
1618}
1619
1620
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001621void StoreIC::GenerateNormal(MacroAssembler* masm) {
1622 // ----------- S t a t e -------------
1623 // -- r0 : value
1624 // -- r1 : receiver
1625 // -- r2 : name
1626 // -- lr : return address
1627 // -----------------------------------
1628 Label miss;
1629
1630 GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1631
1632 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
1633 __ IncrementCounter(&Counters::store_normal_hit, 1, r4, r5);
1634 __ Ret();
1635
1636 __ bind(&miss);
1637 __ IncrementCounter(&Counters::store_normal_miss, 1, r4, r5);
1638 GenerateMiss(masm);
1639}
1640
1641
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001642void StoreIC::GenerateGlobalProxy(MacroAssembler* masm) {
1643 // ----------- S t a t e -------------
1644 // -- r0 : value
1645 // -- r1 : receiver
1646 // -- r2 : name
1647 // -- lr : return address
1648 // -----------------------------------
1649
1650 __ Push(r1, r2, r0);
1651
1652 // Do tail-call to runtime routine.
1653 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
1654}
1655
1656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657#undef __
1658
1659
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001660Condition CompareIC::ComputeCondition(Token::Value op) {
1661 switch (op) {
1662 case Token::EQ_STRICT:
1663 case Token::EQ:
1664 return eq;
1665 case Token::LT:
1666 return lt;
1667 case Token::GT:
1668 // Reverse left and right operands to obtain ECMA-262 conversion order.
1669 return lt;
1670 case Token::LTE:
1671 // Reverse left and right operands to obtain ECMA-262 conversion order.
1672 return ge;
1673 case Token::GTE:
1674 return ge;
1675 default:
1676 UNREACHABLE();
ager@chromium.org378b34e2011-01-28 08:04:38 +00001677 return kNoCondition;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678 }
1679}
1680
1681
1682void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1683 HandleScope scope;
1684 Handle<Code> rewritten;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001685 State previous_state = GetState();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001686 State state = TargetState(previous_state, false, x, y);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001687 if (state == GENERIC) {
1688 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1689 rewritten = stub.GetCode();
1690 } else {
1691 ICCompareStub stub(op_, state);
1692 rewritten = stub.GetCode();
1693 }
1694 set_target(*rewritten);
1695
1696#ifdef DEBUG
1697 if (FLAG_trace_ic) {
1698 PrintF("[CompareIC (%s->%s)#%s]\n",
1699 GetStateName(previous_state),
1700 GetStateName(state),
1701 Token::Name(op_));
1702 }
1703#endif
1704}
1705
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001706
1707void PatchInlinedSmiCode(Address address) {
ager@chromium.org378b34e2011-01-28 08:04:38 +00001708 // Currently there is no smi inlining in the ARM full code generator.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001709}
1710
1711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001712} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001713
1714#endif // V8_TARGET_ARCH_ARM