blob: 0fc6818703375b649d8d31cd543058c0eed237f3 [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) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000118 // Assert that name contains a string.
119 if (FLAG_debug_code) __ AbortIfNotString(name);
120
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000121 // Compute the capacity mask.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000122 const int kCapacityOffset = StringDictionary::kHeaderSize +
123 StringDictionary::kCapacityIndex * kPointerSize;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000124 __ ldr(scratch1, FieldMemOperand(elements, kCapacityOffset));
125 __ mov(scratch1, Operand(scratch1, ASR, kSmiTagSize)); // convert smi to int
126 __ sub(scratch1, scratch1, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000127
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000128 const int kElementsStartOffset = StringDictionary::kHeaderSize +
129 StringDictionary::kElementsStartIndex * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130
131 // Generate an unrolled loop that performs a few probes before
132 // giving up. Measurements done on Gmail indicate that 2 probes
133 // cover ~93% of loads from dictionaries.
134 static const int kProbes = 4;
135 for (int i = 0; i < kProbes; i++) {
136 // Compute the masked index: (hash + i + i * i) & mask.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000137 __ ldr(scratch2, FieldMemOperand(name, String::kHashFieldOffset));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000138 if (i > 0) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000139 // Add the probe offset (i + i * i) left shifted to avoid right shifting
140 // the hash in a separate instruction. The value hash + i + i * i is right
141 // shifted in the following and instruction.
142 ASSERT(StringDictionary::GetProbeOffset(i) <
143 1 << (32 - String::kHashFieldOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000144 __ add(scratch2, scratch2, Operand(
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000145 StringDictionary::GetProbeOffset(i) << String::kHashShift));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000146 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000147 __ and_(scratch2, scratch1, Operand(scratch2, LSR, String::kHashShift));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148
149 // Scale the index by multiplying by the element size.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000150 ASSERT(StringDictionary::kEntrySize == 3);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000151 // scratch2 = scratch2 * 3.
152 __ add(scratch2, scratch2, Operand(scratch2, LSL, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153
154 // Check if the key is identical to the name.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000155 __ add(scratch2, elements, Operand(scratch2, LSL, 2));
156 __ ldr(ip, FieldMemOperand(scratch2, kElementsStartOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000157 __ cmp(name, Operand(ip));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 if (i != kProbes - 1) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000159 __ b(eq, done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000160 } else {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000161 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 }
163 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000164}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000166
167// Helper function used from LoadIC/CallIC GenerateNormal.
168//
169// elements: Property dictionary. It is not clobbered if a jump to the miss
170// label is done.
171// name: Property name. It is not clobbered if a jump to the miss label is
172// done
173// result: Register for the result. It is only updated if a jump to the miss
174// label is not done. Can be the same as elements or name clobbering
175// one of these in the case of not jumping to the miss label.
176// The two scratch registers need to be different from elements, name and
177// result.
178// The generated code assumes that the receiver has slow properties,
179// is not a global object and does not have interceptors.
180static void GenerateDictionaryLoad(MacroAssembler* masm,
181 Label* miss,
182 Register elements,
183 Register name,
184 Register result,
185 Register scratch1,
186 Register scratch2) {
187 // Main use of the scratch registers.
188 // scratch1: Used as temporary and to hold the capacity of the property
189 // dictionary.
190 // scratch2: Used as temporary.
191 Label done;
192
193 // Probe the dictionary.
194 GenerateStringDictionaryProbes(masm,
195 miss,
196 &done,
197 elements,
198 name,
199 scratch1,
200 scratch2);
201
202 // If probing finds an entry check that the value is a normal
203 // property.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000204 __ bind(&done); // scratch2 == elements + 4 * index
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000205 const int kElementsStartOffset = StringDictionary::kHeaderSize +
206 StringDictionary::kElementsStartIndex * kPointerSize;
207 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
208 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000209 __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000210 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000211
212 // Get the value at the masked, scaled index and return.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000213 __ ldr(result,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000214 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000215}
216
217
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000218// Helper function used from StoreIC::GenerateNormal.
219//
220// elements: Property dictionary. It is not clobbered if a jump to the miss
221// label is done.
222// name: Property name. It is not clobbered if a jump to the miss label is
223// done
224// value: The value to store.
225// The two scratch registers need to be different from elements, name and
226// result.
227// The generated code assumes that the receiver has slow properties,
228// is not a global object and does not have interceptors.
229static void GenerateDictionaryStore(MacroAssembler* masm,
230 Label* miss,
231 Register elements,
232 Register name,
233 Register value,
234 Register scratch1,
235 Register scratch2) {
236 // Main use of the scratch registers.
237 // scratch1: Used as temporary and to hold the capacity of the property
238 // dictionary.
239 // scratch2: Used as temporary.
240 Label done;
241
242 // Probe the dictionary.
243 GenerateStringDictionaryProbes(masm,
244 miss,
245 &done,
246 elements,
247 name,
248 scratch1,
249 scratch2);
250
251 // If probing finds an entry in the dictionary check that the value
252 // is a normal property that is not read only.
253 __ bind(&done); // scratch2 == elements + 4 * index
254 const int kElementsStartOffset = StringDictionary::kHeaderSize +
255 StringDictionary::kElementsStartIndex * kPointerSize;
256 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
257 const int kTypeAndReadOnlyMask
258 = (PropertyDetails::TypeField::mask() |
259 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
260 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
261 __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
262 __ b(ne, miss);
263
264 // Store the value at the masked, scaled index and return.
265 const int kValueOffset = kElementsStartOffset + kPointerSize;
266 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
267 __ str(value, MemOperand(scratch2));
268
269 // Update the write barrier. Make sure not to clobber the value.
270 __ mov(scratch1, value);
271 __ RecordWrite(elements, scratch2, scratch1);
272}
273
274
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000275static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
276 Label* miss,
277 Register elements,
278 Register key,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000279 Register result,
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000280 Register t0,
281 Register t1,
282 Register t2) {
283 // Register use:
284 //
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000285 // elements - holds the slow-case elements of the receiver on entry.
286 // Unchanged unless 'result' is the same register.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000287 //
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000288 // key - holds the smi key on entry.
289 // Unchanged unless 'result' is the same register.
290 //
291 // result - holds the result on exit if the load succeeded.
292 // Allowed to be the same as 'key' or 'result'.
293 // Unchanged on bailout so 'key' or 'result' can be used
294 // in further computation.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000295 //
296 // Scratch registers:
297 //
298 // t0 - holds the untagged key on entry and holds the hash once computed.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000299 //
300 // t1 - used to hold the capacity mask of the dictionary
301 //
302 // t2 - used for the index into the dictionary.
303 Label done;
304
305 // Compute the hash code from the untagged key. This must be kept in sync
306 // with ComputeIntegerHash in utils.h.
307 //
308 // hash = ~hash + (hash << 15);
309 __ mvn(t1, Operand(t0));
310 __ add(t0, t1, Operand(t0, LSL, 15));
311 // hash = hash ^ (hash >> 12);
312 __ eor(t0, t0, Operand(t0, LSR, 12));
313 // hash = hash + (hash << 2);
314 __ add(t0, t0, Operand(t0, LSL, 2));
315 // hash = hash ^ (hash >> 4);
316 __ eor(t0, t0, Operand(t0, LSR, 4));
317 // hash = hash * 2057;
318 __ mov(t1, Operand(2057));
319 __ mul(t0, t0, t1);
320 // hash = hash ^ (hash >> 16);
321 __ eor(t0, t0, Operand(t0, LSR, 16));
322
323 // Compute the capacity mask.
324 __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
325 __ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
326 __ sub(t1, t1, Operand(1));
327
328 // Generate an unrolled loop that performs a few probes before giving up.
329 static const int kProbes = 4;
330 for (int i = 0; i < kProbes; i++) {
331 // Use t2 for index calculations and keep the hash intact in t0.
332 __ mov(t2, t0);
333 // Compute the masked index: (hash + i + i * i) & mask.
334 if (i > 0) {
335 __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
336 }
337 __ and_(t2, t2, Operand(t1));
338
339 // Scale the index by multiplying by the element size.
340 ASSERT(NumberDictionary::kEntrySize == 3);
341 __ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
342
343 // Check if the key is identical to the name.
344 __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
345 __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
346 __ cmp(key, Operand(ip));
347 if (i != kProbes - 1) {
348 __ b(eq, &done);
349 } else {
350 __ b(ne, miss);
351 }
352 }
353
354 __ bind(&done);
355 // Check that the value is a normal property.
356 // t2: elements + (index * kPointerSize)
357 const int kDetailsOffset =
358 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
359 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
360 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
361 __ b(ne, miss);
362
363 // Get the value at the masked, scaled index and return.
364 const int kValueOffset =
365 NumberDictionary::kElementsStartOffset + kPointerSize;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000366 __ ldr(result, FieldMemOperand(t2, kValueOffset));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000367}
368
369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000370void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
371 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 // -- r2 : name
373 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000374 // -- r0 : receiver
375 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000376 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000377 Label miss;
378
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000379 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000381 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000382}
383
384
ager@chromium.org378b34e2011-01-28 08:04:38 +0000385void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387 // -- r2 : name
388 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000389 // -- r0 : receiver
390 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000392 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393
ager@chromium.org378b34e2011-01-28 08:04:38 +0000394 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
395 support_wrappers);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 // Cache miss: Jump to runtime.
397 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000398 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399}
400
401
402void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
403 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 // -- r2 : name
405 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000406 // -- r0 : receiver
407 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408 // -----------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000409 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000411 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
412 __ bind(&miss);
413 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414}
415
416
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000417// Checks the receiver for special cases (value type, slow case bits).
418// Falls through for regular JS object.
419static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
420 Register receiver,
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000421 Register map,
422 Register scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000423 int interceptor_bit,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000424 Label* slow) {
425 // Check that the object isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000426 __ JumpIfSmi(receiver, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000427 // Get the map of the receiver.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000428 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000429 // Check bit field.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000430 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
431 __ tst(scratch,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000432 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
ager@chromium.org378b34e2011-01-28 08:04:38 +0000433 __ b(ne, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000434 // Check that the object is some kind of JS object EXCEPT JS Value type.
435 // In the case that the object is a value-wrapper object,
436 // we enter the runtime system to make sure that indexing into string
437 // objects work as intended.
438 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000439 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
440 __ cmp(scratch, Operand(JS_OBJECT_TYPE));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000441 __ b(lt, slow);
442}
443
444
445// Loads an indexed element from a fast case array.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446// If not_fast_array is NULL, doesn't perform the elements map check.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000447static void GenerateFastArrayLoad(MacroAssembler* masm,
448 Register receiver,
449 Register key,
450 Register elements,
451 Register scratch1,
452 Register scratch2,
453 Register result,
454 Label* not_fast_array,
455 Label* out_of_range) {
456 // Register use:
457 //
458 // receiver - holds the receiver on entry.
459 // Unchanged unless 'result' is the same register.
460 //
461 // key - holds the smi key on entry.
462 // Unchanged unless 'result' is the same register.
463 //
464 // elements - holds the elements of the receiver on exit.
465 //
466 // result - holds the result on exit if the load succeeded.
467 // Allowed to be the the same as 'receiver' or 'key'.
468 // Unchanged on bailout so 'receiver' and 'key' can be safely
469 // used by further computation.
470 //
471 // Scratch registers:
472 //
473 // scratch1 - used to hold elements map and elements length.
474 // Holds the elements map if not_fast_array branch is taken.
475 //
476 // scratch2 - used to hold the loaded value.
477
478 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 if (not_fast_array != NULL) {
480 // Check that the object is in fast mode and writable.
481 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
482 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
483 __ cmp(scratch1, ip);
484 __ b(ne, not_fast_array);
485 } else {
486 __ AssertFastElements(elements);
487 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000488 // Check that the key (index) is within bounds.
489 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
490 __ cmp(key, Operand(scratch1));
491 __ b(hs, out_of_range);
492 // Fast case: Do the load.
493 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
494 // The key is a smi.
495 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
496 __ ldr(scratch2,
497 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
498 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
499 __ cmp(scratch2, ip);
500 // In case the loaded value is the_hole we have to consult GetProperty
501 // to ensure the prototype chain is searched.
502 __ b(eq, out_of_range);
503 __ mov(result, scratch2);
504}
505
506
507// Checks whether a key is an array index string or a symbol string.
508// Falls through if a key is a symbol.
509static void GenerateKeyStringCheck(MacroAssembler* masm,
510 Register key,
511 Register map,
512 Register hash,
513 Label* index_string,
514 Label* not_symbol) {
515 // The key is not a smi.
516 // Is it a string?
517 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
518 __ b(ge, not_symbol);
519
520 // Is the string an array index, with cached numeric value?
521 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
522 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
523 __ b(eq, index_string);
524
525 // Is the string a symbol?
526 // map: key map
527 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
528 ASSERT(kSymbolTag != 0);
529 __ tst(hash, Operand(kIsSymbolMask));
530 __ b(eq, not_symbol);
531}
532
533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534// Defined in ic.cc.
535Object* CallIC_Miss(Arguments args);
536
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000537// The generated code does not accept smi keys.
538// The generated code falls through if both probes miss.
539static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
540 int argc,
541 Code::Kind kind) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 // ----------- S t a t e -------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000543 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000544 // -- r2 : name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 // -----------------------------------
546 Label number, non_number, non_string, boolean, probe, miss;
547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 // Probe the stub cache.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +0000549 Code::Flags flags = Code::ComputeFlags(kind,
550 NOT_IN_LOOP,
551 MONOMORPHIC,
552 Code::kNoExtraICState,
553 NORMAL,
554 argc);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000555 StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556
557 // If the stub cache probing failed, the receiver might be a value.
558 // For value objects, we use the map of the prototype objects for
559 // the corresponding JSValue for the cache and that is what we need
560 // to probe.
561 //
562 // Check for number.
563 __ tst(r1, Operand(kSmiTagMask));
564 __ b(eq, &number);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000565 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 __ b(ne, &non_number);
567 __ bind(&number);
568 StubCompiler::GenerateLoadGlobalFunctionPrototype(
569 masm, Context::NUMBER_FUNCTION_INDEX, r1);
570 __ b(&probe);
571
572 // Check for string.
573 __ bind(&non_number);
574 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
575 __ b(hs, &non_string);
576 StubCompiler::GenerateLoadGlobalFunctionPrototype(
577 masm, Context::STRING_FUNCTION_INDEX, r1);
578 __ b(&probe);
579
580 // Check for boolean.
581 __ bind(&non_string);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000582 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
583 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000584 __ b(eq, &boolean);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000585 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
586 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000587 __ b(ne, &miss);
588 __ bind(&boolean);
589 StubCompiler::GenerateLoadGlobalFunctionPrototype(
590 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
591
592 // Probe the stub cache for the value object.
593 __ bind(&probe);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000594 StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597}
598
599
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000600static void GenerateFunctionTailCall(MacroAssembler* masm,
601 int argc,
602 Label* miss,
603 Register scratch) {
604 // r1: function
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000605
606 // Check that the value isn't a smi.
607 __ tst(r1, Operand(kSmiTagMask));
608 __ b(eq, miss);
609
610 // Check that the value is a JSFunction.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000611 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000612 __ b(ne, miss);
613
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000614 // Invoke the function.
615 ParameterCount actual(argc);
616 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
617}
618
619
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000620static void GenerateCallNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000621 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000622 // -- r2 : name
623 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000624 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000625 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626
mads.s.ager31e71382008-08-13 09:32:07 +0000627 // Get the receiver of the function from the stack into r1.
628 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000630 GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000632 // r0: elements
633 // Search the dictionary - put result in register r1.
634 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000636 GenerateFunctionTailCall(masm, argc, &miss, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000638 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639}
640
641
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000642static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000643 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000644 // -- r2 : name
645 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 // -----------------------------------
647
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000648 if (id == IC::kCallIC_Miss) {
649 __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
650 } else {
651 __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
652 }
653
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000654 // Get the receiver of the function from the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +0000655 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000656
657 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658
659 // Push the receiver and the name of the function.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000660 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000661
662 // Call the entry.
mads.s.ager31e71382008-08-13 09:32:07 +0000663 __ mov(r0, Operand(2));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000664 __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665
ager@chromium.orga1645e22009-09-09 19:27:10 +0000666 CEntryStub stub(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667 __ CallStub(&stub);
668
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000669 // Move result to r1 and leave the internal frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 __ mov(r1, Operand(r0));
ager@chromium.org236ad962008-09-25 09:45:57 +0000671 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000673 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000674 // This can happen only for regular CallIC but not KeyedCallIC.
675 if (id == IC::kCallIC_Miss) {
676 Label invoke, global;
677 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
678 __ tst(r2, Operand(kSmiTagMask));
679 __ b(eq, &invoke);
680 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
681 __ b(eq, &global);
682 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
683 __ b(ne, &invoke);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000684
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000685 // Patch the receiver on the stack.
686 __ bind(&global);
687 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
688 __ str(r2, MemOperand(sp, argc * kPointerSize));
689 __ bind(&invoke);
690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000691
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000692 // Invoke the function.
693 ParameterCount actual(argc);
694 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695}
696
697
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000698void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
699 // ----------- S t a t e -------------
700 // -- r2 : name
701 // -- lr : return address
702 // -----------------------------------
703
704 GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
705}
706
707
708void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
709 // ----------- S t a t e -------------
710 // -- r2 : name
711 // -- lr : return address
712 // -----------------------------------
713
714 // Get the receiver of the function from the stack into r1.
715 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
716 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
717 GenerateMiss(masm, argc);
718}
719
720
721void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
722 // ----------- S t a t e -------------
723 // -- r2 : name
724 // -- lr : return address
725 // -----------------------------------
726
727 GenerateCallNormal(masm, argc);
728 GenerateMiss(masm, argc);
729}
730
731
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000732void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000733 // ----------- S t a t e -------------
734 // -- r2 : name
735 // -- lr : return address
736 // -----------------------------------
737
738 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000739}
740
741
742void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000743 // ----------- S t a t e -------------
744 // -- r2 : name
745 // -- lr : return address
746 // -----------------------------------
747
748 // Get the receiver of the function from the stack into r1.
749 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
750
751 Label do_call, slow_call, slow_load, slow_reload_receiver;
752 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
753 Label index_smi, index_string;
754
755 // Check that the key is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +0000756 __ JumpIfNotSmi(r2, &check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000757 __ bind(&index_smi);
758 // Now the key is known to be a smi. This place is also jumped to from below
759 // where a numeric string is converted to a smi.
760
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000761 GenerateKeyedLoadReceiverCheck(
762 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000763
764 GenerateFastArrayLoad(
765 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
766 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
767
768 __ bind(&do_call);
769 // receiver in r1 is not used after this point.
770 // r2: key
771 // r1: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000772 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000773
774 __ bind(&check_number_dictionary);
775 // r2: key
776 // r3: elements map
777 // r4: elements
778 // Check whether the elements is a number dictionary.
779 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
780 __ cmp(r3, ip);
781 __ b(ne, &slow_load);
782 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
783 // r0: untagged index
784 GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
785 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
786 __ jmp(&do_call);
787
788 __ bind(&slow_load);
789 // This branch is taken when calling KeyedCallIC_Miss is neither required
790 // nor beneficial.
791 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
792 __ EnterInternalFrame();
793 __ push(r2); // save the key
794 __ Push(r1, r2); // pass the receiver and the key
795 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
796 __ pop(r2); // restore the key
797 __ LeaveInternalFrame();
798 __ mov(r1, r0);
799 __ jmp(&do_call);
800
801 __ bind(&check_string);
802 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
803
804 // The key is known to be a symbol.
805 // If the receiver is a regular JS object with slow properties then do
806 // a quick inline probe of the receiver's dictionary.
807 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000808 GenerateKeyedLoadReceiverCheck(
809 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000810
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000811 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
812 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000813 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
814 __ cmp(r3, ip);
815 __ b(ne, &lookup_monomorphic_cache);
816
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000817 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000818 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
819 __ jmp(&do_call);
820
821 __ bind(&lookup_monomorphic_cache);
822 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
823 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
824 // Fall through on miss.
825
826 __ bind(&slow_call);
827 // This branch is taken if:
828 // - the receiver requires boxing or access check,
829 // - the key is neither smi nor symbol,
830 // - the value loaded is not a function,
831 // - there is hope that the runtime will create a monomorphic call stub
832 // that will get fetched next time.
833 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
834 GenerateMiss(masm, argc);
835
836 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000837 __ IndexFromHash(r3, r2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000838 // Now jump to the place where smi keys are handled.
839 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000840}
841
842
843void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000844 // ----------- S t a t e -------------
845 // -- r2 : name
846 // -- lr : return address
847 // -----------------------------------
848
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000849 // Check if the name is a string.
850 Label miss;
851 __ tst(r2, Operand(kSmiTagMask));
852 __ b(eq, &miss);
853 __ IsObjectJSStringType(r2, r0, &miss);
854
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000855 GenerateCallNormal(masm, argc);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000856 __ bind(&miss);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000857 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000858}
859
860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861// Defined in ic.cc.
862Object* LoadIC_Miss(Arguments args);
863
864void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
865 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866 // -- r2 : name
867 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000868 // -- r0 : receiver
869 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 // -----------------------------------
871
872 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000873 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
874 NOT_IN_LOOP,
875 MONOMORPHIC);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +0000876 StubCache::GenerateProbe(masm, flags, r0, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877
878 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +0000879 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880}
881
882
883void LoadIC::GenerateNormal(MacroAssembler* masm) {
884 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 // -- r2 : name
886 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000887 // -- r0 : receiver
888 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000890 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000892 GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000893
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000894 // r1: elements
895 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 __ Ret();
897
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000898 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000900 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901}
902
903
904void LoadIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 // -- r2 : name
907 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000908 // -- r0 : receiver
909 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 // -----------------------------------
911
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000912 __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
913
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000914 __ mov(r3, r0);
915 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916
mads.s.ager31e71382008-08-13 09:32:07 +0000917 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000918 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
919 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920}
921
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000922// Returns the code marker, or the 0 if the code is not marked.
923static inline int InlinedICSiteMarker(Address address,
924 Address* inline_end_address) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000925 if (V8::UseCrankshaft()) return false;
926
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000927 // If the instruction after the call site is not the pseudo instruction nop1
928 // then this is not related to an inlined in-object property load. The nop1
929 // instruction is located just after the call to the IC in the deferred code
930 // handling the miss in the inlined code. After the nop1 instruction there is
931 // a branch instruction for jumping back from the deferred code.
932 Address address_after_call = address + Assembler::kCallTargetAddressOffset;
933 Instr instr_after_call = Assembler::instr_at(address_after_call);
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000934 int code_marker = MacroAssembler::GetCodeMarker(instr_after_call);
935
936 // A negative result means the code is not marked.
937 if (code_marker <= 0) return 0;
938
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000939 Address address_after_nop = address_after_call + Assembler::kInstrSize;
940 Instr instr_after_nop = Assembler::instr_at(address_after_nop);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000941 // There may be some reg-reg move and frame merging code to skip over before
942 // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
943 // code.
944 while (!Assembler::IsBranch(instr_after_nop)) {
945 address_after_nop += Assembler::kInstrSize;
946 instr_after_nop = Assembler::instr_at(address_after_nop);
947 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000948
949 // Find the end of the inlined code for handling the load.
950 int b_offset =
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000951 Assembler::GetBranchOffset(instr_after_nop) + Assembler::kPcLoadDelta;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000952 ASSERT(b_offset < 0); // Jumping back from deferred code.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000953 *inline_end_address = address_after_nop + b_offset;
954
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000955 return code_marker;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000956}
957
958
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000959bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000960 if (V8::UseCrankshaft()) return false;
961
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000962 // Find the end of the inlined code for handling the load if this is an
963 // inlined IC call site.
964 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000965 if (InlinedICSiteMarker(address, &inline_end_address)
966 != Assembler::PROPERTY_ACCESS_INLINED) {
967 return false;
968 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000969
970 // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000971 // The immediate must be representable in 12 bits.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000972 ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000973 Address ldr_property_instr_address =
974 inline_end_address - Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000975 ASSERT(Assembler::IsLdrRegisterImmediate(
976 Assembler::instr_at(ldr_property_instr_address)));
977 Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
978 ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
979 ldr_property_instr, offset - kHeapObjectTag);
980 Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
981
982 // Indicate that code has changed.
983 CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
984
985 // Patch the map check.
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000986 // For PROPERTY_ACCESS_INLINED, the load map instruction is generated
987 // 4 instructions before the end of the inlined code.
988 // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
989 int ldr_map_offset = -4;
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000990 Address ldr_map_instr_address =
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000991 inline_end_address + ldr_map_offset * Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000992 Assembler::set_target_address_at(ldr_map_instr_address,
993 reinterpret_cast<Address>(map));
994 return true;
995}
996
997
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000998bool LoadIC::PatchInlinedContextualLoad(Address address,
999 Object* map,
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +00001000 Object* cell,
1001 bool is_dont_delete) {
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001002 // Find the end of the inlined code for handling the contextual load if
1003 // this is inlined IC call site.
1004 Address inline_end_address;
1005 int marker = InlinedICSiteMarker(address, &inline_end_address);
1006 if (!((marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT) ||
1007 (marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE))) {
1008 return false;
1009 }
1010 // On ARM we don't rely on the is_dont_delete argument as the hint is already
1011 // embedded in the code marker.
1012 bool marker_is_dont_delete =
1013 marker == Assembler::PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE;
1014
1015 // These are the offsets from the end of the inlined code.
1016 // See codgen-arm.cc CodeGenerator::EmitNamedLoad.
1017 int ldr_map_offset = marker_is_dont_delete ? -5: -8;
1018 int ldr_cell_offset = marker_is_dont_delete ? -2: -5;
1019 if (FLAG_debug_code && marker_is_dont_delete) {
1020 // Three extra instructions were generated to check for the_hole_value.
1021 ldr_map_offset -= 3;
1022 ldr_cell_offset -= 3;
1023 }
1024 Address ldr_map_instr_address =
1025 inline_end_address + ldr_map_offset * Assembler::kInstrSize;
1026 Address ldr_cell_instr_address =
1027 inline_end_address + ldr_cell_offset * Assembler::kInstrSize;
1028
1029 // Patch the map check.
1030 Assembler::set_target_address_at(ldr_map_instr_address,
1031 reinterpret_cast<Address>(map));
1032 // Patch the cell address.
1033 Assembler::set_target_address_at(ldr_cell_instr_address,
1034 reinterpret_cast<Address>(cell));
1035
1036 return true;
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001037}
1038
1039
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001040bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001041 if (V8::UseCrankshaft()) return false;
1042
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001043 // Find the end of the inlined code for the store if there is an
1044 // inlined version of the store.
1045 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001046 if (InlinedICSiteMarker(address, &inline_end_address)
1047 != Assembler::PROPERTY_ACCESS_INLINED) {
1048 return false;
1049 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00001050
1051 // Compute the address of the map load instruction.
1052 Address ldr_map_instr_address =
1053 inline_end_address -
1054 (CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
1055 Assembler::kInstrSize);
1056
1057 // Update the offsets if initializing the inlined store. No reason
1058 // to update the offsets when clearing the inlined version because
1059 // it will bail out in the map check.
1060 if (map != Heap::null_value()) {
1061 // Patch the offset in the actual store instruction.
1062 Address str_property_instr_address =
1063 ldr_map_instr_address + 3 * Assembler::kInstrSize;
1064 Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
1065 ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
1066 str_property_instr = Assembler::SetStrRegisterImmediateOffset(
1067 str_property_instr, offset - kHeapObjectTag);
1068 Assembler::instr_at_put(str_property_instr_address, str_property_instr);
1069
1070 // Patch the offset in the add instruction that is part of the
1071 // write barrier.
1072 Address add_offset_instr_address =
1073 str_property_instr_address + Assembler::kInstrSize;
1074 Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
1075 ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
1076 add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
1077 add_offset_instr, offset - kHeapObjectTag);
1078 Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
1079
1080 // Indicate that code has changed.
1081 CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
1082 }
1083
1084 // Patch the map check.
1085 Assembler::set_target_address_at(ldr_map_instr_address,
1086 reinterpret_cast<Address>(map));
1087
1088 return true;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001089}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001090
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001091
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001092bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001093 if (V8::UseCrankshaft()) return false;
1094
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001095 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001096 if (InlinedICSiteMarker(address, &inline_end_address)
1097 != Assembler::PROPERTY_ACCESS_INLINED) {
1098 return false;
1099 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001100
1101 // Patch the map check.
1102 Address ldr_map_instr_address =
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001103 inline_end_address -
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001104 (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001105 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001106 Assembler::set_target_address_at(ldr_map_instr_address,
1107 reinterpret_cast<Address>(map));
1108 return true;
1109}
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001110
1111
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001112bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001113 if (V8::UseCrankshaft()) return false;
1114
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001115 // Find the end of the inlined code for handling the store if this is an
1116 // inlined IC call site.
1117 Address inline_end_address;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001118 if (InlinedICSiteMarker(address, &inline_end_address)
1119 != Assembler::PROPERTY_ACCESS_INLINED) {
1120 return false;
1121 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001122
1123 // Patch the map check.
1124 Address ldr_map_instr_address =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001125 inline_end_address -
1126 (CodeGenerator::kInlinedKeyedStoreInstructionsAfterPatch *
1127 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001128 Assembler::set_target_address_at(ldr_map_instr_address,
1129 reinterpret_cast<Address>(map));
1130 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001131}
1132
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001133
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001134Object* KeyedLoadIC_Miss(Arguments args);
1135
1136
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001138 // ---------- S t a t e --------------
1139 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001140 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001141 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001142 // -----------------------------------
1143
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001144 __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
1145
ager@chromium.orgac091b72010-05-05 07:34:42 +00001146 __ Push(r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001147
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001148 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1149 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001150}
1151
1152
1153void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1154 // ---------- S t a t e --------------
1155 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001156 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001157 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001158 // -----------------------------------
1159
ager@chromium.orgac091b72010-05-05 07:34:42 +00001160 __ Push(r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001161
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001162 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163}
1164
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001165
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001166void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001167 // ---------- S t a t e --------------
1168 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001169 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001170 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001171 // -----------------------------------
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001172 Label slow, check_string, index_smi, index_string, property_array_property;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001173 Label check_pixel_array, probe_dictionary, check_number_dictionary;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001174
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001175 Register key = r0;
1176 Register receiver = r1;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001177
ager@chromium.org5c838252010-02-19 08:53:10 +00001178 // Check that the key is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001179 __ JumpIfNotSmi(key, &check_string);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001180 __ bind(&index_smi);
1181 // Now the key is known to be a smi. This place is also jumped to from below
1182 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001183
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001184 GenerateKeyedLoadReceiverCheck(
1185 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
1186
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001187 // Check the "has fast elements" bit in the receiver's map which is
1188 // now in r2.
1189 __ ldrb(r3, FieldMemOperand(r2, Map::kBitField2Offset));
1190 __ tst(r3, Operand(1 << Map::kHasFastElements));
1191 __ b(eq, &check_pixel_array);
1192
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001193 GenerateFastArrayLoad(
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001194 masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001195 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001196 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001197
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001198 // Check whether the elements is a pixel array.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001199 // r0: key
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001200 // r1: receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001201 __ bind(&check_pixel_array);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001202
1203 GenerateFastPixelArrayLoad(masm,
1204 r1,
1205 r0,
1206 r3,
1207 r4,
1208 r2,
1209 r5,
1210 r0,
1211 &check_number_dictionary,
1212 NULL,
1213 &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001214
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001215 __ bind(&check_number_dictionary);
1216 // Check whether the elements is a number dictionary.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001217 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001218 // r3: elements map
1219 // r4: elements
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001220 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1221 __ cmp(r3, ip);
1222 __ b(ne, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001223 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001224 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001225 __ Ret();
1226
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001227 // Slow case, key and receiver still in r0 and r1.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001228 __ bind(&slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001229 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
ager@chromium.org5c838252010-02-19 08:53:10 +00001230 GenerateRuntimeGetProperty(masm);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001231
1232 __ bind(&check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001233 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001234
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001235 GenerateKeyedLoadReceiverCheck(
1236 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1237
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001238 // If the receiver is a fast-case object, check the keyed lookup
1239 // cache. Otherwise probe the dictionary.
1240 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001241 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001242 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001243 __ cmp(r4, ip);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001244 __ b(eq, &probe_dictionary);
1245
1246 // Load the map of the receiver, compute the keyed lookup cache hash
1247 // based on 32 bits of the map pointer and the string hash.
1248 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1249 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1250 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1251 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001252 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001253
1254 // Load the key (consisting of map and symbol) from the cache and
1255 // check for match.
1256 ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
1257 __ mov(r4, Operand(cache_keys));
1258 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1259 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
1260 __ cmp(r2, r5);
1261 __ b(ne, &slow);
1262 __ ldr(r5, MemOperand(r4));
1263 __ cmp(r0, r5);
1264 __ b(ne, &slow);
1265
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001266 // Get field offset.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001267 // r0 : key
1268 // r1 : receiver
1269 // r2 : receiver's map
1270 // r3 : lookup cache index
1271 ExternalReference cache_field_offsets
1272 = ExternalReference::keyed_lookup_cache_field_offsets();
1273 __ mov(r4, Operand(cache_field_offsets));
1274 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1275 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001276 __ sub(r5, r5, r6, SetCC);
1277 __ b(ge, &property_array_property);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001278
1279 // Load in-object property.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001280 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1281 __ add(r6, r6, r5); // Index from start of object.
1282 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1283 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1284 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1285 __ Ret();
1286
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001287 // Load property array property.
1288 __ bind(&property_array_property);
1289 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1290 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1291 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
1292 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1293 __ Ret();
1294
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001295 // Do a quick inline probe of the receiver's dictionary, if it
1296 // exists.
1297 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001298 // r1: receiver
1299 // r0: key
1300 // r3: elements
1301 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1302 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1303 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001304 // Load the property to r0.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001305 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001306 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
1307 __ Ret();
1308
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001309 __ bind(&index_string);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001310 __ IndexFromHash(r3, key);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001311 // Now jump to the place where smi keys are handled.
1312 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001313}
1314
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001315
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001316void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1317 // ---------- S t a t e --------------
1318 // -- lr : return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001319 // -- r0 : key (index)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001320 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001321 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001322 Label miss;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001323
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001324 Register receiver = r1;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001325 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001326 Register scratch1 = r2;
1327 Register scratch2 = r3;
1328 Register result = r0;
ager@chromium.org357bf652010-04-12 11:30:10 +00001329
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001330 StringCharAtGenerator char_at_generator(receiver,
1331 index,
1332 scratch1,
1333 scratch2,
1334 result,
1335 &miss, // When not a string.
1336 &miss, // When not a number.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001337 &miss, // When index out of range.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001338 STRING_INDEX_IS_ARRAY_INDEX);
1339 char_at_generator.GenerateFast(masm);
1340 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +00001341
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001342 StubRuntimeCallHelper call_helper;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001343 char_at_generator.GenerateSlow(masm, call_helper);
ager@chromium.org357bf652010-04-12 11:30:10 +00001344
ager@chromium.org357bf652010-04-12 11:30:10 +00001345 __ bind(&miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001346 GenerateMiss(masm);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001347}
1348
1349
ager@chromium.org5c838252010-02-19 08:53:10 +00001350void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1351 // ---------- S t a t e --------------
1352 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001353 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001354 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001355 // -----------------------------------
1356 Label slow;
1357
ager@chromium.org5c838252010-02-19 08:53:10 +00001358 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001359 __ JumpIfSmi(r1, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001360
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00001361 // Check that the key is an array index, that is Uint32.
1362 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1363 __ b(ne, &slow);
ager@chromium.org5c838252010-02-19 08:53:10 +00001364
1365 // Get the map of the receiver.
1366 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1367
1368 // Check that it has indexed interceptor and access checks
1369 // are not enabled for this object.
1370 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1371 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1372 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1373 __ b(ne, &slow);
1374
1375 // Everything is fine, call runtime.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001376 __ Push(r1, r0); // Receiver, key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001377
1378 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001379 __ TailCallExternalReference(ExternalReference(
ager@chromium.org5c838252010-02-19 08:53:10 +00001380 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
1381
1382 __ bind(&slow);
1383 GenerateMiss(masm);
1384}
1385
1386
1387void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001388 // ---------- S t a t e --------------
1389 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001390 // -- r1 : key
1391 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001392 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001393 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001394
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001395 // Push receiver, key and value for runtime call.
1396 __ Push(r2, r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001397
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001398 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1399 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001400}
1401
1402
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001403void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1404 StrictModeFlag strict_mode) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001405 // ---------- S t a t e --------------
1406 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001407 // -- r1 : key
1408 // -- r2 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001409 // -- lr : return address
ager@chromium.org5c838252010-02-19 08:53:10 +00001410 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001411
1412 // Push receiver, key and value for runtime call.
1413 __ Push(r2, r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001414
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001415 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1416 __ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1417 __ Push(r1, r0);
1418
1419 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420}
1421
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001422
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001423void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1424 StrictModeFlag strict_mode) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001425 // ---------- S t a t e --------------
1426 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001427 // -- r1 : key
1428 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001429 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001430 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001431 Label slow, fast, array, extra, check_pixel_array;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001432
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001433 // Register usage.
1434 Register value = r0;
1435 Register key = r1;
1436 Register receiver = r2;
1437 Register elements = r3; // Elements array of the receiver.
1438 // r4 and r5 are used as general scratch registers.
1439
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001440 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001441 __ tst(key, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001442 __ b(ne, &slow);
1443 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001444 __ tst(receiver, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001445 __ b(eq, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001446 // Get the map of the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001447 __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001448 // Check that the receiver does not require access checks. We need
1449 // to do this because this generic stub does not perform map checks.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001450 __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001451 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1452 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001453 // Check if the object is a JS array or not.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001454 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
1455 __ cmp(r4, Operand(JS_ARRAY_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001456 __ b(eq, &array);
1457 // Check that the object is some kind of JS object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001458 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001459 __ b(lt, &slow);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001460
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001461 // Object case: Check key against length in the elements array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001462 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001463 // Check that the object is in fast mode and writable.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001464 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001465 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001466 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001467 __ b(ne, &check_pixel_array);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001468 // Check array bounds. Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001469 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001470 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001471 __ b(lo, &fast);
1472
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001473 // Slow case, handle jump to runtime.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001474 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001475 // Entry registers are intact.
1476 // r0: value.
1477 // r1: key.
1478 // r2: receiver.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001479 GenerateRuntimeSetProperty(masm, strict_mode);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001480
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001481 // Check whether the elements is a pixel array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001482 // r4: elements map.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001483 __ bind(&check_pixel_array);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001484 GenerateFastPixelArrayStore(masm,
1485 r2,
1486 r1,
1487 r0,
1488 elements,
1489 r4,
1490 r5,
1491 r6,
1492 false,
1493 false,
1494 NULL,
1495 &slow,
1496 &slow,
1497 &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001498
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001499 // Extra capacity case: Check if there is extra capacity to
1500 // perform the store and update the length. Used for adding one
1501 // element to the array by writing to array[array.length].
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001502 __ bind(&extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001503 // Condition code from comparing key and array length is still available.
1504 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1505 // Check for room in the elements backing store.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001506 // Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001507 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001508 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001509 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001510 // Calculate key + 1 as smi.
1511 ASSERT_EQ(0, kSmiTag);
1512 __ add(r4, key, Operand(Smi::FromInt(1)));
1513 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001514 __ b(&fast);
1515
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001516 // Array case: Get the length and the elements array from the JS
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001517 // array. Check that the array is in fast mode (and writable); if it
1518 // is the length is always a smi.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001519 __ bind(&array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001520 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1521 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001522 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001523 __ cmp(r4, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001524 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001525
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001526 // Check the key against the length in the array.
1527 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1528 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001529 __ b(hs, &extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001530 // Fall through to fast case.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001531
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001532 __ bind(&fast);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001533 // Fast case, store the value to the elements backing store.
1534 __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1535 __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1536 __ str(value, MemOperand(r5));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001537 // Skip write barrier if the written value is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001538 __ tst(value, Operand(kSmiTagMask));
1539 __ Ret(eq);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001540 // Update write barrier for the elements array address.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001541 __ sub(r4, r5, Operand(elements));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001542 __ RecordWrite(elements, Operand(r4), r5, r6);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001543
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001544 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545}
1546
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001547
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001548void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001549 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 // ----------- S t a t e -------------
1551 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001552 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 // -- r2 : name
1554 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 // -----------------------------------
1556
1557 // Get the receiver from the stack and probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001558 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1559 NOT_IN_LOOP,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001560 MONOMORPHIC,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001561 strict_mode);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001562 StubCache::GenerateProbe(masm, flags, r1, r2, r3, r4, r5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563
1564 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001565 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566}
1567
1568
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001569void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570 // ----------- S t a t e -------------
1571 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001572 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573 // -- r2 : name
1574 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 // -----------------------------------
1576
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001577 __ Push(r1, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
mads.s.ager31e71382008-08-13 09:32:07 +00001579 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001580 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1581 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582}
1583
1584
ager@chromium.org5c838252010-02-19 08:53:10 +00001585void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1586 // ----------- S t a t e -------------
1587 // -- r0 : value
1588 // -- r1 : receiver
1589 // -- r2 : name
1590 // -- lr : return address
1591 // -----------------------------------
1592 //
1593 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1594 // (currently anything except for external and pixel arrays which means
1595 // anything with elements of FixedArray type.), but currently is restricted
1596 // to JSArray.
1597 // Value must be a number, but only smis are accepted as the most common case.
1598
1599 Label miss;
1600
1601 Register receiver = r1;
1602 Register value = r0;
1603 Register scratch = r3;
1604
1605 // Check that the receiver isn't a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001606 __ JumpIfSmi(receiver, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001607
1608 // Check that the object is a JS array.
1609 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1610 __ b(ne, &miss);
1611
1612 // Check that elements are FixedArray.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001613 // We rely on StoreIC_ArrayLength below to deal with all types of
1614 // fast elements (including COW).
ager@chromium.org5c838252010-02-19 08:53:10 +00001615 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1616 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1617 __ b(ne, &miss);
1618
1619 // Check that value is a smi.
ager@chromium.org378b34e2011-01-28 08:04:38 +00001620 __ JumpIfNotSmi(value, &miss);
ager@chromium.org5c838252010-02-19 08:53:10 +00001621
1622 // Prepare tail call to StoreIC_ArrayLength.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001623 __ Push(receiver, value);
ager@chromium.org5c838252010-02-19 08:53:10 +00001624
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001625 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1626 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001627
1628 __ bind(&miss);
1629
1630 GenerateMiss(masm);
1631}
1632
1633
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001634void StoreIC::GenerateNormal(MacroAssembler* masm) {
1635 // ----------- S t a t e -------------
1636 // -- r0 : value
1637 // -- r1 : receiver
1638 // -- r2 : name
1639 // -- lr : return address
1640 // -----------------------------------
1641 Label miss;
1642
1643 GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1644
1645 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
1646 __ IncrementCounter(&Counters::store_normal_hit, 1, r4, r5);
1647 __ Ret();
1648
1649 __ bind(&miss);
1650 __ IncrementCounter(&Counters::store_normal_miss, 1, r4, r5);
1651 GenerateMiss(masm);
1652}
1653
1654
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001655void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1656 StrictModeFlag strict_mode) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001657 // ----------- S t a t e -------------
1658 // -- r0 : value
1659 // -- r1 : receiver
1660 // -- r2 : name
1661 // -- lr : return address
1662 // -----------------------------------
1663
1664 __ Push(r1, r2, r0);
1665
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001666 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1667 __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1668 __ Push(r1, r0);
1669
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001670 // Do tail-call to runtime routine.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001671 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001672}
1673
1674
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675#undef __
1676
1677
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001678Condition CompareIC::ComputeCondition(Token::Value op) {
1679 switch (op) {
1680 case Token::EQ_STRICT:
1681 case Token::EQ:
1682 return eq;
1683 case Token::LT:
1684 return lt;
1685 case Token::GT:
1686 // Reverse left and right operands to obtain ECMA-262 conversion order.
1687 return lt;
1688 case Token::LTE:
1689 // Reverse left and right operands to obtain ECMA-262 conversion order.
1690 return ge;
1691 case Token::GTE:
1692 return ge;
1693 default:
1694 UNREACHABLE();
ager@chromium.org378b34e2011-01-28 08:04:38 +00001695 return kNoCondition;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001696 }
1697}
1698
1699
1700void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1701 HandleScope scope;
1702 Handle<Code> rewritten;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001703 State previous_state = GetState();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001704 State state = TargetState(previous_state, false, x, y);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001705 if (state == GENERIC) {
1706 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1707 rewritten = stub.GetCode();
1708 } else {
1709 ICCompareStub stub(op_, state);
1710 rewritten = stub.GetCode();
1711 }
1712 set_target(*rewritten);
1713
1714#ifdef DEBUG
1715 if (FLAG_trace_ic) {
1716 PrintF("[CompareIC (%s->%s)#%s]\n",
1717 GetStateName(previous_state),
1718 GetStateName(state),
1719 Token::Name(op_));
1720 }
1721#endif
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001722
1723 // Activate inlined smi code.
1724 if (previous_state == UNINITIALIZED) {
1725 PatchInlinedSmiCode(address());
1726 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001727}
1728
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001729
1730void PatchInlinedSmiCode(Address address) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001731 Address cmp_instruction_address =
1732 address + Assembler::kCallTargetAddressOffset;
1733
1734 // If the instruction following the call is not a cmp rx, #yyy, nothing
1735 // was inlined.
1736 Instr instr = Assembler::instr_at(cmp_instruction_address);
1737 if (!Assembler::IsCmpImmediate(instr)) {
1738 return;
1739 }
1740
1741 // The delta to the start of the map check instruction and the
1742 // condition code uses at the patched jump.
1743 int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1744 delta +=
1745 Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1746 // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1747 // nothing was inlined.
1748 if (delta == 0) {
1749 return;
1750 }
1751
1752#ifdef DEBUG
1753 if (FLAG_trace_ic) {
1754 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
1755 address, cmp_instruction_address, delta);
1756 }
1757#endif
1758
1759 Address patch_address =
1760 cmp_instruction_address - delta * Instruction::kInstrSize;
1761 Instr instr_at_patch = Assembler::instr_at(patch_address);
1762 Instr branch_instr =
1763 Assembler::instr_at(patch_address + Instruction::kInstrSize);
1764 ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1765 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1766 Assembler::GetRm(instr_at_patch).code());
1767 ASSERT(Assembler::IsBranch(branch_instr));
1768 if (Assembler::GetCondition(branch_instr) == eq) {
1769 // This is patching a "jump if not smi" site to be active.
1770 // Changing
1771 // cmp rx, rx
1772 // b eq, <target>
1773 // to
1774 // tst rx, #kSmiTagMask
1775 // b ne, <target>
1776 CodePatcher patcher(patch_address, 2);
1777 Register reg = Assembler::GetRn(instr_at_patch);
1778 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1779 patcher.EmitCondition(ne);
1780 } else {
1781 ASSERT(Assembler::GetCondition(branch_instr) == ne);
1782 // This is patching a "jump if smi" site to be active.
1783 // Changing
1784 // cmp rx, rx
1785 // b ne, <target>
1786 // to
1787 // tst rx, #kSmiTagMask
1788 // b eq, <target>
1789 CodePatcher patcher(patch_address, 2);
1790 Register reg = Assembler::GetRn(instr_at_patch);
1791 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1792 patcher.EmitCondition(eq);
1793 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001794}
1795
1796
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001798
1799#endif // V8_TARGET_ARCH_ARM