blob: e7e3de3cdb93c6bd6524c63419cee68ec39d94f0 [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"
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +000033#include "codegen.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)));
98 __ b(nz, miss);
99
100 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
101 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
102 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
103 __ cmp(t1, ip);
104 __ b(nz, miss);
105}
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
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000382void LoadIC::GenerateStringLength(MacroAssembler* masm) {
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.org5c838252010-02-19 08:53:10 +0000391 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392 // Cache miss: Jump to runtime.
393 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000394 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395}
396
397
398void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
399 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000400 // -- r2 : name
401 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000402 // -- r0 : receiver
403 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 // -----------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000405 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000406
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000407 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
408 __ bind(&miss);
409 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410}
411
412
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000413// Checks the receiver for special cases (value type, slow case bits).
414// Falls through for regular JS object.
415static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
416 Register receiver,
417 Register scratch1,
418 Register scratch2,
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000419 int interceptor_bit,
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000420 Label* slow) {
421 // Check that the object isn't a smi.
422 __ BranchOnSmi(receiver, slow);
423 // Get the map of the receiver.
424 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
425 // Check bit field.
426 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000427 __ tst(scratch2,
428 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
429 __ b(nz, slow);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000430 // Check that the object is some kind of JS object EXCEPT JS Value type.
431 // In the case that the object is a value-wrapper object,
432 // we enter the runtime system to make sure that indexing into string
433 // objects work as intended.
434 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
435 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
436 __ cmp(scratch1, Operand(JS_OBJECT_TYPE));
437 __ b(lt, slow);
438}
439
440
441// Loads an indexed element from a fast case array.
442static void GenerateFastArrayLoad(MacroAssembler* masm,
443 Register receiver,
444 Register key,
445 Register elements,
446 Register scratch1,
447 Register scratch2,
448 Register result,
449 Label* not_fast_array,
450 Label* out_of_range) {
451 // Register use:
452 //
453 // receiver - holds the receiver on entry.
454 // Unchanged unless 'result' is the same register.
455 //
456 // key - holds the smi key on entry.
457 // Unchanged unless 'result' is the same register.
458 //
459 // elements - holds the elements of the receiver on exit.
460 //
461 // result - holds the result on exit if the load succeeded.
462 // Allowed to be the the same as 'receiver' or 'key'.
463 // Unchanged on bailout so 'receiver' and 'key' can be safely
464 // used by further computation.
465 //
466 // Scratch registers:
467 //
468 // scratch1 - used to hold elements map and elements length.
469 // Holds the elements map if not_fast_array branch is taken.
470 //
471 // scratch2 - used to hold the loaded value.
472
473 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
474 // Check that the object is in fast mode (not dictionary).
475 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
476 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
477 __ cmp(scratch1, ip);
478 __ b(ne, not_fast_array);
479 // Check that the key (index) is within bounds.
480 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
481 __ cmp(key, Operand(scratch1));
482 __ b(hs, out_of_range);
483 // Fast case: Do the load.
484 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
485 // The key is a smi.
486 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
487 __ ldr(scratch2,
488 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
489 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
490 __ cmp(scratch2, ip);
491 // In case the loaded value is the_hole we have to consult GetProperty
492 // to ensure the prototype chain is searched.
493 __ b(eq, out_of_range);
494 __ mov(result, scratch2);
495}
496
497
498// Checks whether a key is an array index string or a symbol string.
499// Falls through if a key is a symbol.
500static void GenerateKeyStringCheck(MacroAssembler* masm,
501 Register key,
502 Register map,
503 Register hash,
504 Label* index_string,
505 Label* not_symbol) {
506 // The key is not a smi.
507 // Is it a string?
508 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
509 __ b(ge, not_symbol);
510
511 // Is the string an array index, with cached numeric value?
512 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
513 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
514 __ b(eq, index_string);
515
516 // Is the string a symbol?
517 // map: key map
518 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
519 ASSERT(kSymbolTag != 0);
520 __ tst(hash, Operand(kIsSymbolMask));
521 __ b(eq, not_symbol);
522}
523
524
525// Picks out an array index from the hash field.
526static void GenerateIndexFromHash(MacroAssembler* masm,
527 Register key,
528 Register hash) {
529 // Register use:
530 // key - holds the overwritten key on exit.
531 // hash - holds the key's hash. Clobbered.
532
533 // If the hash field contains an array index pick it out. The assert checks
534 // that the constants for the maximum number of digits for an array index
535 // cached in the hash field and the number of bits reserved for it does not
536 // conflict.
537 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
538 (1 << String::kArrayIndexValueBits));
539 // We want the smi-tagged index in key. kArrayIndexValueMask has zeros in
540 // the low kHashShift bits.
541 ASSERT(String::kHashShift >= kSmiTagSize);
542 // Here we actually clobber the key which will be used if calling into
543 // runtime later. However as the new key is the numeric value of a string key
544 // there is no difference in using either key.
545 ASSERT(String::kHashShift >= kSmiTagSize);
546 __ Ubfx(hash, hash, String::kHashShift, String::kArrayIndexValueBits);
547 __ mov(key, Operand(hash, LSL, kSmiTagSize));
548}
549
550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551// Defined in ic.cc.
552Object* CallIC_Miss(Arguments args);
553
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000554// The generated code does not accept smi keys.
555// The generated code falls through if both probes miss.
556static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
557 int argc,
558 Code::Kind kind) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 // ----------- S t a t e -------------
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000560 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000561 // -- r2 : name
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000562 // -----------------------------------
563 Label number, non_number, non_string, boolean, probe, miss;
564
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565 // Probe the stub cache.
566 Code::Flags flags =
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000567 Code::ComputeFlags(kind, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000568 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569
570 // If the stub cache probing failed, the receiver might be a value.
571 // For value objects, we use the map of the prototype objects for
572 // the corresponding JSValue for the cache and that is what we need
573 // to probe.
574 //
575 // Check for number.
576 __ tst(r1, Operand(kSmiTagMask));
577 __ b(eq, &number);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000578 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 __ b(ne, &non_number);
580 __ bind(&number);
581 StubCompiler::GenerateLoadGlobalFunctionPrototype(
582 masm, Context::NUMBER_FUNCTION_INDEX, r1);
583 __ b(&probe);
584
585 // Check for string.
586 __ bind(&non_number);
587 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
588 __ b(hs, &non_string);
589 StubCompiler::GenerateLoadGlobalFunctionPrototype(
590 masm, Context::STRING_FUNCTION_INDEX, r1);
591 __ b(&probe);
592
593 // Check for boolean.
594 __ bind(&non_string);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000595 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
596 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597 __ b(eq, &boolean);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000598 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
599 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000600 __ b(ne, &miss);
601 __ bind(&boolean);
602 StubCompiler::GenerateLoadGlobalFunctionPrototype(
603 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
604
605 // Probe the stub cache for the value object.
606 __ bind(&probe);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000607 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000610}
611
612
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000613static void GenerateFunctionTailCall(MacroAssembler* masm,
614 int argc,
615 Label* miss,
616 Register scratch) {
617 // r1: function
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000618
619 // Check that the value isn't a smi.
620 __ tst(r1, Operand(kSmiTagMask));
621 __ b(eq, miss);
622
623 // Check that the value is a JSFunction.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000624 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000625 __ b(ne, miss);
626
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000627 // Invoke the function.
628 ParameterCount actual(argc);
629 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
630}
631
632
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000633static void GenerateCallNormal(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000634 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000635 // -- r2 : name
636 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000637 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000638 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639
mads.s.ager31e71382008-08-13 09:32:07 +0000640 // Get the receiver of the function from the stack into r1.
641 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000643 GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000644
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000645 // r0: elements
646 // Search the dictionary - put result in register r1.
647 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000648
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000649 GenerateFunctionTailCall(masm, argc, &miss, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651 __ bind(&miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652}
653
654
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000655static void GenerateCallMiss(MacroAssembler* masm, int argc, IC::UtilityId id) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000656 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000657 // -- r2 : name
658 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659 // -----------------------------------
660
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000661 if (id == IC::kCallIC_Miss) {
662 __ IncrementCounter(&Counters::call_miss, 1, r3, r4);
663 } else {
664 __ IncrementCounter(&Counters::keyed_call_miss, 1, r3, r4);
665 }
666
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000667 // Get the receiver of the function from the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +0000668 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000669
670 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671
672 // Push the receiver and the name of the function.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000673 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674
675 // Call the entry.
mads.s.ager31e71382008-08-13 09:32:07 +0000676 __ mov(r0, Operand(2));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000677 __ mov(r1, Operand(ExternalReference(IC_Utility(id))));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000678
ager@chromium.orga1645e22009-09-09 19:27:10 +0000679 CEntryStub stub(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000680 __ CallStub(&stub);
681
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000682 // Move result to r1 and leave the internal frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 __ mov(r1, Operand(r0));
ager@chromium.org236ad962008-09-25 09:45:57 +0000684 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000685
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000686 // Check if the receiver is a global object of some sort.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000687 // This can happen only for regular CallIC but not KeyedCallIC.
688 if (id == IC::kCallIC_Miss) {
689 Label invoke, global;
690 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
691 __ tst(r2, Operand(kSmiTagMask));
692 __ b(eq, &invoke);
693 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
694 __ b(eq, &global);
695 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
696 __ b(ne, &invoke);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000697
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000698 // Patch the receiver on the stack.
699 __ bind(&global);
700 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
701 __ str(r2, MemOperand(sp, argc * kPointerSize));
702 __ bind(&invoke);
703 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000705 // Invoke the function.
706 ParameterCount actual(argc);
707 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708}
709
710
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000711void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
712 // ----------- S t a t e -------------
713 // -- r2 : name
714 // -- lr : return address
715 // -----------------------------------
716
717 GenerateCallMiss(masm, argc, IC::kCallIC_Miss);
718}
719
720
721void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
722 // ----------- S t a t e -------------
723 // -- r2 : name
724 // -- lr : return address
725 // -----------------------------------
726
727 // Get the receiver of the function from the stack into r1.
728 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
729 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC);
730 GenerateMiss(masm, argc);
731}
732
733
734void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
735 // ----------- S t a t e -------------
736 // -- r2 : name
737 // -- lr : return address
738 // -----------------------------------
739
740 GenerateCallNormal(masm, argc);
741 GenerateMiss(masm, argc);
742}
743
744
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000745void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000746 // ----------- S t a t e -------------
747 // -- r2 : name
748 // -- lr : return address
749 // -----------------------------------
750
751 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000752}
753
754
755void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000756 // ----------- S t a t e -------------
757 // -- r2 : name
758 // -- lr : return address
759 // -----------------------------------
760
761 // Get the receiver of the function from the stack into r1.
762 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
763
764 Label do_call, slow_call, slow_load, slow_reload_receiver;
765 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
766 Label index_smi, index_string;
767
768 // Check that the key is a smi.
769 __ BranchOnNotSmi(r2, &check_string);
770 __ bind(&index_smi);
771 // Now the key is known to be a smi. This place is also jumped to from below
772 // where a numeric string is converted to a smi.
773
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000774 GenerateKeyedLoadReceiverCheck(
775 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000776
777 GenerateFastArrayLoad(
778 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
779 __ IncrementCounter(&Counters::keyed_call_generic_smi_fast, 1, r0, r3);
780
781 __ bind(&do_call);
782 // receiver in r1 is not used after this point.
783 // r2: key
784 // r1: function
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000785 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000786
787 __ bind(&check_number_dictionary);
788 // r2: key
789 // r3: elements map
790 // r4: elements
791 // Check whether the elements is a number dictionary.
792 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
793 __ cmp(r3, ip);
794 __ b(ne, &slow_load);
795 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
796 // r0: untagged index
797 GenerateNumberDictionaryLoad(masm, &slow_load, r4, r2, r1, r0, r3, r5);
798 __ IncrementCounter(&Counters::keyed_call_generic_smi_dict, 1, r0, r3);
799 __ jmp(&do_call);
800
801 __ bind(&slow_load);
802 // This branch is taken when calling KeyedCallIC_Miss is neither required
803 // nor beneficial.
804 __ IncrementCounter(&Counters::keyed_call_generic_slow_load, 1, r0, r3);
805 __ EnterInternalFrame();
806 __ push(r2); // save the key
807 __ Push(r1, r2); // pass the receiver and the key
808 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
809 __ pop(r2); // restore the key
810 __ LeaveInternalFrame();
811 __ mov(r1, r0);
812 __ jmp(&do_call);
813
814 __ bind(&check_string);
815 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
816
817 // The key is known to be a symbol.
818 // If the receiver is a regular JS object with slow properties then do
819 // a quick inline probe of the receiver's dictionary.
820 // Otherwise do the monomorphic cache probe.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000821 GenerateKeyedLoadReceiverCheck(
822 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000823
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000824 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
825 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000826 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
827 __ cmp(r3, ip);
828 __ b(ne, &lookup_monomorphic_cache);
829
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000830 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000831 __ IncrementCounter(&Counters::keyed_call_generic_lookup_dict, 1, r0, r3);
832 __ jmp(&do_call);
833
834 __ bind(&lookup_monomorphic_cache);
835 __ IncrementCounter(&Counters::keyed_call_generic_lookup_cache, 1, r0, r3);
836 GenerateMonomorphicCacheProbe(masm, argc, Code::KEYED_CALL_IC);
837 // Fall through on miss.
838
839 __ bind(&slow_call);
840 // This branch is taken if:
841 // - the receiver requires boxing or access check,
842 // - the key is neither smi nor symbol,
843 // - the value loaded is not a function,
844 // - there is hope that the runtime will create a monomorphic call stub
845 // that will get fetched next time.
846 __ IncrementCounter(&Counters::keyed_call_generic_slow, 1, r0, r3);
847 GenerateMiss(masm, argc);
848
849 __ bind(&index_string);
850 GenerateIndexFromHash(masm, r2, r3);
851 // Now jump to the place where smi keys are handled.
852 __ jmp(&index_smi);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000853}
854
855
856void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000857 // ----------- S t a t e -------------
858 // -- r2 : name
859 // -- lr : return address
860 // -----------------------------------
861
862 GenerateCallNormal(masm, argc);
863 GenerateMiss(masm, argc);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000864}
865
866
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867// Defined in ic.cc.
868Object* LoadIC_Miss(Arguments args);
869
870void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
871 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 // -- r2 : name
873 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000874 // -- r0 : receiver
875 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876 // -----------------------------------
877
878 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000879 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
880 NOT_IN_LOOP,
881 MONOMORPHIC);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000882 StubCache::GenerateProbe(masm, flags, r0, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883
884 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +0000885 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886}
887
888
889void LoadIC::GenerateNormal(MacroAssembler* masm) {
890 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 // -- r2 : name
892 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000893 // -- r0 : receiver
894 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 // -----------------------------------
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000896 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000898 GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000900 // r1: elements
901 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 __ Ret();
903
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000904 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000906 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000907}
908
909
910void LoadIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 // -- r2 : name
913 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000914 // -- r0 : receiver
915 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916 // -----------------------------------
917
fschneider@chromium.org40b9da32010-06-28 11:29:21 +0000918 __ IncrementCounter(&Counters::load_miss, 1, r3, r4);
919
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000920 __ mov(r3, r0);
921 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000922
mads.s.ager31e71382008-08-13 09:32:07 +0000923 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000924 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
925 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926}
927
928
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000929static inline bool IsInlinedICSite(Address address,
930 Address* inline_end_address) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000931 // If the instruction after the call site is not the pseudo instruction nop1
932 // then this is not related to an inlined in-object property load. The nop1
933 // instruction is located just after the call to the IC in the deferred code
934 // handling the miss in the inlined code. After the nop1 instruction there is
935 // a branch instruction for jumping back from the deferred code.
936 Address address_after_call = address + Assembler::kCallTargetAddressOffset;
937 Instr instr_after_call = Assembler::instr_at(address_after_call);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000938 if (!Assembler::IsNop(instr_after_call, PROPERTY_ACCESS_INLINED)) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000939 return false;
940 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000941 Address address_after_nop = address_after_call + Assembler::kInstrSize;
942 Instr instr_after_nop = Assembler::instr_at(address_after_nop);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000943 // There may be some reg-reg move and frame merging code to skip over before
944 // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
945 // code.
946 while (!Assembler::IsBranch(instr_after_nop)) {
947 address_after_nop += Assembler::kInstrSize;
948 instr_after_nop = Assembler::instr_at(address_after_nop);
949 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000950
951 // Find the end of the inlined code for handling the load.
952 int b_offset =
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000953 Assembler::GetBranchOffset(instr_after_nop) + Assembler::kPcLoadDelta;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000954 ASSERT(b_offset < 0); // Jumping back from deferred code.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000955 *inline_end_address = address_after_nop + b_offset;
956
957 return true;
958}
959
960
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000961bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
962 // 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;
965 if (!IsInlinedICSite(address, &inline_end_address)) return false;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000966
967 // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000968 // The immediate must be representable in 12 bits.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000969 ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000970 Address ldr_property_instr_address =
971 inline_end_address - Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000972 ASSERT(Assembler::IsLdrRegisterImmediate(
973 Assembler::instr_at(ldr_property_instr_address)));
974 Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
975 ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
976 ldr_property_instr, offset - kHeapObjectTag);
977 Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
978
979 // Indicate that code has changed.
980 CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
981
982 // Patch the map check.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000983 Address ldr_map_instr_address =
984 inline_end_address - 4 * Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000985 Assembler::set_target_address_at(ldr_map_instr_address,
986 reinterpret_cast<Address>(map));
987 return true;
988}
989
990
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000991bool StoreIC::PatchInlinedStore(Address address, Object* map, int offset) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000992 // Find the end of the inlined code for the store if there is an
993 // inlined version of the store.
994 Address inline_end_address;
995 if (!IsInlinedICSite(address, &inline_end_address)) return false;
996
997 // Compute the address of the map load instruction.
998 Address ldr_map_instr_address =
999 inline_end_address -
1000 (CodeGenerator::GetInlinedNamedStoreInstructionsAfterPatch() *
1001 Assembler::kInstrSize);
1002
1003 // Update the offsets if initializing the inlined store. No reason
1004 // to update the offsets when clearing the inlined version because
1005 // it will bail out in the map check.
1006 if (map != Heap::null_value()) {
1007 // Patch the offset in the actual store instruction.
1008 Address str_property_instr_address =
1009 ldr_map_instr_address + 3 * Assembler::kInstrSize;
1010 Instr str_property_instr = Assembler::instr_at(str_property_instr_address);
1011 ASSERT(Assembler::IsStrRegisterImmediate(str_property_instr));
1012 str_property_instr = Assembler::SetStrRegisterImmediateOffset(
1013 str_property_instr, offset - kHeapObjectTag);
1014 Assembler::instr_at_put(str_property_instr_address, str_property_instr);
1015
1016 // Patch the offset in the add instruction that is part of the
1017 // write barrier.
1018 Address add_offset_instr_address =
1019 str_property_instr_address + Assembler::kInstrSize;
1020 Instr add_offset_instr = Assembler::instr_at(add_offset_instr_address);
1021 ASSERT(Assembler::IsAddRegisterImmediate(add_offset_instr));
1022 add_offset_instr = Assembler::SetAddRegisterImmediateOffset(
1023 add_offset_instr, offset - kHeapObjectTag);
1024 Assembler::instr_at_put(add_offset_instr_address, add_offset_instr);
1025
1026 // Indicate that code has changed.
1027 CPU::FlushICache(str_property_instr_address, 2 * Assembler::kInstrSize);
1028 }
1029
1030 // Patch the map check.
1031 Assembler::set_target_address_at(ldr_map_instr_address,
1032 reinterpret_cast<Address>(map));
1033
1034 return true;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001035}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001036
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001037
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001038bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
1039 Address inline_end_address;
1040 if (!IsInlinedICSite(address, &inline_end_address)) return false;
1041
1042 // Patch the map check.
1043 Address ldr_map_instr_address =
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +00001044 inline_end_address -
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001045 (CodeGenerator::GetInlinedKeyedLoadInstructionsAfterPatch() *
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001046 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001047 Assembler::set_target_address_at(ldr_map_instr_address,
1048 reinterpret_cast<Address>(map));
1049 return true;
1050}
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00001051
1052
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001053bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001054 // Find the end of the inlined code for handling the store if this is an
1055 // inlined IC call site.
1056 Address inline_end_address;
1057 if (!IsInlinedICSite(address, &inline_end_address)) return false;
1058
1059 // Patch the map check.
1060 Address ldr_map_instr_address =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001061 inline_end_address -
1062 (CodeGenerator::kInlinedKeyedStoreInstructionsAfterPatch *
1063 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001064 Assembler::set_target_address_at(ldr_map_instr_address,
1065 reinterpret_cast<Address>(map));
1066 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00001067}
1068
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001069
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001070Object* KeyedLoadIC_Miss(Arguments args);
1071
1072
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001074 // ---------- S t a t e --------------
1075 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001076 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001077 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001078 // -----------------------------------
1079
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001080 __ IncrementCounter(&Counters::keyed_load_miss, 1, r3, r4);
1081
ager@chromium.orgac091b72010-05-05 07:34:42 +00001082 __ Push(r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001084 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
1085 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001086}
1087
1088
1089void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
1090 // ---------- S t a t e --------------
1091 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001092 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001093 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001094 // -----------------------------------
1095
ager@chromium.orgac091b72010-05-05 07:34:42 +00001096 __ Push(r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001097
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001098 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001103 // ---------- S t a t e --------------
1104 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001105 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001106 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001107 // -----------------------------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001108 Label slow, check_string, index_smi, index_string;
1109 Label check_pixel_array, probe_dictionary, check_number_dictionary;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001110
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001111 Register key = r0;
1112 Register receiver = r1;
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001113
ager@chromium.org5c838252010-02-19 08:53:10 +00001114 // Check that the key is a smi.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001115 __ BranchOnNotSmi(key, &check_string);
1116 __ bind(&index_smi);
1117 // Now the key is known to be a smi. This place is also jumped to from below
1118 // where a numeric string is converted to a smi.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001119
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001120 GenerateKeyedLoadReceiverCheck(
1121 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
1122
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001123 GenerateFastArrayLoad(
1124 masm, receiver, key, r4, r3, r2, r0, &check_pixel_array, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001125 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001126 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001127
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001128 // Check whether the elements is a pixel array.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001129 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001130 // r3: elements map
1131 // r4: elements
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001132 __ bind(&check_pixel_array);
1133 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
1134 __ cmp(r3, ip);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001135 __ b(ne, &check_number_dictionary);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001136 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001137 __ mov(r2, Operand(key, ASR, kSmiTagSize));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001138 __ cmp(r2, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001139 __ b(hs, &slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001140 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset));
1141 __ ldrb(r2, MemOperand(ip, r2));
1142 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001143 __ Ret();
1144
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001145 __ bind(&check_number_dictionary);
1146 // Check whether the elements is a number dictionary.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001147 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001148 // r3: elements map
1149 // r4: elements
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001150 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1151 __ cmp(r3, ip);
1152 __ b(ne, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001153 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001154 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r0, r2, r3, r5);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +00001155 __ Ret();
1156
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001157 // Slow case, key and receiver still in r0 and r1.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001158 __ bind(&slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001159 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
ager@chromium.org5c838252010-02-19 08:53:10 +00001160 GenerateRuntimeGetProperty(masm);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001161
1162 __ bind(&check_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001163 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001164
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001165 GenerateKeyedLoadReceiverCheck(
1166 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1167
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001168 // If the receiver is a fast-case object, check the keyed lookup
1169 // cache. Otherwise probe the dictionary.
1170 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001171 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001172 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001173 __ cmp(r4, ip);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001174 __ b(eq, &probe_dictionary);
1175
1176 // Load the map of the receiver, compute the keyed lookup cache hash
1177 // based on 32 bits of the map pointer and the string hash.
1178 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1179 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1180 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1181 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001182 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001183
1184 // Load the key (consisting of map and symbol) from the cache and
1185 // check for match.
1186 ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
1187 __ mov(r4, Operand(cache_keys));
1188 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1189 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
1190 __ cmp(r2, r5);
1191 __ b(ne, &slow);
1192 __ ldr(r5, MemOperand(r4));
1193 __ cmp(r0, r5);
1194 __ b(ne, &slow);
1195
1196 // Get field offset and check that it is an in-object property.
1197 // r0 : key
1198 // r1 : receiver
1199 // r2 : receiver's map
1200 // r3 : lookup cache index
1201 ExternalReference cache_field_offsets
1202 = ExternalReference::keyed_lookup_cache_field_offsets();
1203 __ mov(r4, Operand(cache_field_offsets));
1204 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1205 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
1206 __ cmp(r5, r6);
1207 __ b(ge, &slow);
1208
1209 // Load in-object property.
1210 __ sub(r5, r5, r6); // Index from end of object.
1211 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1212 __ add(r6, r6, r5); // Index from start of object.
1213 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1214 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
1215 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
1216 __ Ret();
1217
1218 // Do a quick inline probe of the receiver's dictionary, if it
1219 // exists.
1220 __ bind(&probe_dictionary);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001221 // r1: receiver
1222 // r0: key
1223 // r3: elements
1224 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1225 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1226 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001227 // Load the property to r0.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00001228 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001229 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
1230 __ Ret();
1231
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001232 __ bind(&index_string);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001233 GenerateIndexFromHash(masm, key, r3);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +00001234 // Now jump to the place where smi keys are handled.
1235 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236}
1237
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001238
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001239void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1240 // ---------- S t a t e --------------
1241 // -- lr : return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001242 // -- r0 : key (index)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001243 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001244 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +00001245 Label miss;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001246 Label index_out_of_range;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001247
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001248 Register receiver = r1;
ager@chromium.orgac091b72010-05-05 07:34:42 +00001249 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001250 Register scratch1 = r2;
1251 Register scratch2 = r3;
1252 Register result = r0;
ager@chromium.org357bf652010-04-12 11:30:10 +00001253
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001254 StringCharAtGenerator char_at_generator(receiver,
1255 index,
1256 scratch1,
1257 scratch2,
1258 result,
1259 &miss, // When not a string.
1260 &miss, // When not a number.
1261 &index_out_of_range,
1262 STRING_INDEX_IS_ARRAY_INDEX);
1263 char_at_generator.GenerateFast(masm);
1264 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +00001265
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001266 ICRuntimeCallHelper call_helper;
1267 char_at_generator.GenerateSlow(masm, call_helper);
ager@chromium.org357bf652010-04-12 11:30:10 +00001268
ager@chromium.orgac091b72010-05-05 07:34:42 +00001269 __ bind(&index_out_of_range);
1270 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
1271 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +00001272
1273 __ bind(&miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001274 GenerateMiss(masm);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001275}
1276
1277
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001278// Convert unsigned integer with specified number of leading zeroes in binary
1279// representation to IEEE 754 double.
1280// Integer to convert is passed in register hiword.
1281// Resulting double is returned in registers hiword:loword.
1282// This functions does not work correctly for 0.
1283static void GenerateUInt2Double(MacroAssembler* masm,
1284 Register hiword,
1285 Register loword,
1286 Register scratch,
1287 int leading_zeroes) {
1288 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
1289 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
1290
1291 const int mantissa_shift_for_hi_word =
1292 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
1293
1294 const int mantissa_shift_for_lo_word =
1295 kBitsPerInt - mantissa_shift_for_hi_word;
1296
1297 __ mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
1298 if (mantissa_shift_for_hi_word > 0) {
1299 __ mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word));
1300 __ orr(hiword, scratch, Operand(hiword, LSR, mantissa_shift_for_hi_word));
1301 } else {
1302 __ mov(loword, Operand(0));
1303 __ orr(hiword, scratch, Operand(hiword, LSL, mantissa_shift_for_hi_word));
1304 }
1305
1306 // If least significant bit of biased exponent was not 1 it was corrupted
1307 // by most significant bit of mantissa so we should fix that.
1308 if (!(biased_exponent & 1)) {
1309 __ bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift));
1310 }
1311}
1312
1313
ager@chromium.org3811b432009-10-28 14:53:37 +00001314void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
1315 ExternalArrayType array_type) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001316 // ---------- S t a t e --------------
1317 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001318 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001319 // -- r1 : receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001320 // -----------------------------------
1321 Label slow, failed_allocation;
1322
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001323 Register key = r0;
1324 Register receiver = r1;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001325
1326 // Check that the object isn't a smi
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001327 __ BranchOnSmi(receiver, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001328
1329 // Check that the key is a smi.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001330 __ BranchOnNotSmi(key, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001331
1332 // Check that the object is a JS object. Load map into r2.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001333 __ CompareObjectType(receiver, r2, r3, FIRST_JS_OBJECT_TYPE);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001334 __ b(lt, &slow);
1335
1336 // Check that the receiver does not require access checks. We need
1337 // to check this explicitly since this generic stub does not perform
1338 // map checks.
1339 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1340 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
1341 __ b(ne, &slow);
1342
1343 // Check that the elements array is the appropriate type of
1344 // ExternalArray.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001345 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
1346 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001347 __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
1348 __ cmp(r2, ip);
1349 __ b(ne, &slow);
1350
1351 // Check that the index is in range.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001352 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
1353 __ cmp(ip, Operand(key, ASR, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001354 // Unsigned comparison catches both negative and too-large values.
1355 __ b(lo, &slow);
1356
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001357 // r3: elements array
1358 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
1359 // r3: base pointer of external storage
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001360
1361 // We are not untagging smi key and instead work with it
1362 // as if it was premultiplied by 2.
1363 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
1364
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001365 Register value = r2;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001366 switch (array_type) {
1367 case kExternalByteArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001368 __ ldrsb(value, MemOperand(r3, key, LSR, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001369 break;
1370 case kExternalUnsignedByteArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001371 __ ldrb(value, MemOperand(r3, key, LSR, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001372 break;
1373 case kExternalShortArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001374 __ ldrsh(value, MemOperand(r3, key, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001375 break;
1376 case kExternalUnsignedShortArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001377 __ ldrh(value, MemOperand(r3, key, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001378 break;
1379 case kExternalIntArray:
1380 case kExternalUnsignedIntArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001381 __ ldr(value, MemOperand(r3, key, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001382 break;
1383 case kExternalFloatArray:
1384 if (CpuFeatures::IsSupported(VFP3)) {
1385 CpuFeatures::Scope scope(VFP3);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001386 __ add(r2, r3, Operand(key, LSL, 1));
1387 __ vldr(s0, r2, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001388 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001389 __ ldr(value, MemOperand(r3, key, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001390 }
1391 break;
1392 default:
1393 UNREACHABLE();
1394 break;
1395 }
1396
1397 // For integer array types:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001398 // r2: value
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001399 // For floating-point array type
1400 // s0: value (if VFP3 is supported)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001401 // r2: value (if VFP3 is not supported)
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001402
1403 if (array_type == kExternalIntArray) {
1404 // For the Int and UnsignedInt array types, we need to see whether
1405 // the value can be represented in a Smi. If not, we need to convert
1406 // it to a HeapNumber.
1407 Label box_int;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001408 __ cmp(value, Operand(0xC0000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001409 __ b(mi, &box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001410 // Tag integer as smi and return it.
1411 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001412 __ Ret();
1413
1414 __ bind(&box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001415 // Allocate a HeapNumber for the result and perform int-to-double
1416 // conversion. Use r0 for result as key is not needed any more.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001417 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
1418 __ AllocateHeapNumber(r0, r3, r4, r6, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001419
1420 if (CpuFeatures::IsSupported(VFP3)) {
1421 CpuFeatures::Scope scope(VFP3);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001422 __ vmov(s0, value);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001423 __ vcvt_f64_s32(d0, s0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001424 __ sub(r3, r0, Operand(kHeapObjectTag));
1425 __ vstr(d0, r3, HeapNumber::kValueOffset);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001426 __ Ret();
1427 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001428 WriteInt32ToHeapNumberStub stub(value, r0, r3);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001429 __ TailCallStub(&stub);
1430 }
1431 } else if (array_type == kExternalUnsignedIntArray) {
1432 // The test is different for unsigned int values. Since we need
1433 // the value to be in the range of a positive smi, we can't
1434 // handle either of the top two bits being set in the value.
1435 if (CpuFeatures::IsSupported(VFP3)) {
1436 CpuFeatures::Scope scope(VFP3);
1437 Label box_int, done;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001438 __ tst(value, Operand(0xC0000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001439 __ b(ne, &box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001440 // Tag integer as smi and return it.
1441 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001442 __ Ret();
1443
1444 __ bind(&box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001445 __ vmov(s0, value);
1446 // Allocate a HeapNumber for the result and perform int-to-double
1447 // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all
1448 // registers - also when jumping due to exhausted young space.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001449 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
1450 __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001451
1452 __ vcvt_f64_u32(d0, s0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001453 __ sub(r1, r2, Operand(kHeapObjectTag));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001454 __ vstr(d0, r1, HeapNumber::kValueOffset);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001455
1456 __ mov(r0, r2);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001457 __ Ret();
1458 } else {
1459 // Check whether unsigned integer fits into smi.
1460 Label box_int_0, box_int_1, done;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001461 __ tst(value, Operand(0x80000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001462 __ b(ne, &box_int_0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001463 __ tst(value, Operand(0x40000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001464 __ b(ne, &box_int_1);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001465 // Tag integer as smi and return it.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001466 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001467 __ Ret();
1468
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001469 Register hiword = value; // r2.
1470 Register loword = r3;
1471
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001472 __ bind(&box_int_0);
1473 // Integer does not have leading zeros.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001474 GenerateUInt2Double(masm, hiword, loword, r4, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001475 __ b(&done);
1476
1477 __ bind(&box_int_1);
1478 // Integer has one leading zero.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001479 GenerateUInt2Double(masm, hiword, loword, r4, 1);
1480
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001481
1482 __ bind(&done);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001483 // Integer was converted to double in registers hiword:loword.
1484 // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber
1485 // clobbers all registers - also when jumping due to exhausted young
1486 // space.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001487 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
1488 __ AllocateHeapNumber(r4, r5, r7, r6, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001489
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001490 __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset));
1491 __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001492
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001493 __ mov(r0, r4);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001494 __ Ret();
1495 }
1496 } else if (array_type == kExternalFloatArray) {
1497 // For the floating-point array type, we need to always allocate a
1498 // HeapNumber.
1499 if (CpuFeatures::IsSupported(VFP3)) {
1500 CpuFeatures::Scope scope(VFP3);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001501 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
1502 // AllocateHeapNumber clobbers all registers - also when jumping due to
1503 // exhausted young space.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001504 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
1505 __ AllocateHeapNumber(r2, r3, r4, r6, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001506 __ vcvt_f64_f32(d0, s0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001507 __ sub(r1, r2, Operand(kHeapObjectTag));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001508 __ vstr(d0, r1, HeapNumber::kValueOffset);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001509
1510 __ mov(r0, r2);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001511 __ Ret();
1512 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001513 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
1514 // AllocateHeapNumber clobbers all registers - also when jumping due to
1515 // exhausted young space.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001516 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
1517 __ AllocateHeapNumber(r3, r4, r5, r6, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001518 // VFP is not available, do manual single to double conversion.
1519
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001520 // r2: floating point value (binary32)
1521 // r3: heap number for result
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001522
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001523 // Extract mantissa to r0. OK to clobber r0 now as there are no jumps to
1524 // the slow case from here.
1525 __ and_(r0, value, Operand(kBinary32MantissaMask));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001526
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001527 // Extract exponent to r1. OK to clobber r1 now as there are no jumps to
1528 // the slow case from here.
1529 __ mov(r1, Operand(value, LSR, kBinary32MantissaBits));
1530 __ and_(r1, r1, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001531
1532 Label exponent_rebiased;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001533 __ teq(r1, Operand(0x00));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001534 __ b(eq, &exponent_rebiased);
1535
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001536 __ teq(r1, Operand(0xff));
1537 __ mov(r1, Operand(0x7ff), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001538 __ b(eq, &exponent_rebiased);
1539
1540 // Rebias exponent.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001541 __ add(r1,
1542 r1,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001543 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
1544
1545 __ bind(&exponent_rebiased);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001546 __ and_(r2, value, Operand(kBinary32SignMask));
1547 value = no_reg;
1548 __ orr(r2, r2, Operand(r1, LSL, HeapNumber::kMantissaBitsInTopWord));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001549
1550 // Shift mantissa.
1551 static const int kMantissaShiftForHiWord =
1552 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
1553
1554 static const int kMantissaShiftForLoWord =
1555 kBitsPerInt - kMantissaShiftForHiWord;
1556
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001557 __ orr(r2, r2, Operand(r0, LSR, kMantissaShiftForHiWord));
1558 __ mov(r0, Operand(r0, LSL, kMantissaShiftForLoWord));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001559
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001560 __ str(r2, FieldMemOperand(r3, HeapNumber::kExponentOffset));
1561 __ str(r0, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
1562
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001563 __ mov(r0, r3);
1564 __ Ret();
1565 }
1566
1567 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001568 // Tag integer as smi and return it.
1569 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001570 __ Ret();
1571 }
1572
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001573 // Slow case, key and receiver still in r0 and r1.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001574 __ bind(&slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001575 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1, r2, r3);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001576 GenerateRuntimeGetProperty(masm);
ager@chromium.org3811b432009-10-28 14:53:37 +00001577}
1578
1579
ager@chromium.org5c838252010-02-19 08:53:10 +00001580void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1581 // ---------- S t a t e --------------
1582 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001583 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001584 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001585 // -----------------------------------
1586 Label slow;
1587
ager@chromium.org5c838252010-02-19 08:53:10 +00001588 // Check that the receiver isn't a smi.
1589 __ BranchOnSmi(r1, &slow);
1590
1591 // Check that the key is a smi.
1592 __ BranchOnNotSmi(r0, &slow);
1593
1594 // Get the map of the receiver.
1595 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1596
1597 // Check that it has indexed interceptor and access checks
1598 // are not enabled for this object.
1599 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1600 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1601 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1602 __ b(ne, &slow);
1603
1604 // Everything is fine, call runtime.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001605 __ Push(r1, r0); // Receiver, key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001606
1607 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001608 __ TailCallExternalReference(ExternalReference(
ager@chromium.org5c838252010-02-19 08:53:10 +00001609 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
1610
1611 __ bind(&slow);
1612 GenerateMiss(masm);
1613}
1614
1615
1616void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001617 // ---------- S t a t e --------------
1618 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001619 // -- r1 : key
1620 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001621 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001622 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001623
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001624 // Push receiver, key and value for runtime call.
1625 __ Push(r2, r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001626
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001627 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1628 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001629}
1630
1631
1632void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1633 // ---------- S t a t e --------------
1634 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001635 // -- r1 : key
1636 // -- r2 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001637 // -- lr : return address
ager@chromium.org5c838252010-02-19 08:53:10 +00001638 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001639
1640 // Push receiver, key and value for runtime call.
1641 __ Push(r2, r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001643 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644}
1645
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001648 // ---------- S t a t e --------------
1649 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001650 // -- r1 : key
1651 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001652 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001653 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001654 Label slow, fast, array, extra, check_pixel_array;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001655
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001656 // Register usage.
1657 Register value = r0;
1658 Register key = r1;
1659 Register receiver = r2;
1660 Register elements = r3; // Elements array of the receiver.
1661 // r4 and r5 are used as general scratch registers.
1662
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001663 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001664 __ tst(key, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001665 __ b(ne, &slow);
1666 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001667 __ tst(receiver, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001668 __ b(eq, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001669 // Get the map of the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001670 __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001671 // Check that the receiver does not require access checks. We need
1672 // to do this because this generic stub does not perform map checks.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001673 __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001674 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1675 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001676 // Check if the object is a JS array or not.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001677 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
1678 __ cmp(r4, Operand(JS_ARRAY_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001679 __ b(eq, &array);
1680 // Check that the object is some kind of JS object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001681 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001682 __ b(lt, &slow);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001683
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001684 // Object case: Check key against length in the elements array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001685 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001686 // Check that the object is in fast mode (not dictionary).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001687 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001688 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001689 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001690 __ b(ne, &check_pixel_array);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001691 // Check array bounds. Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001692 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001693 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001694 __ b(lo, &fast);
1695
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001696 // Slow case, handle jump to runtime.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001697 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001698 // Entry registers are intact.
1699 // r0: value.
1700 // r1: key.
1701 // r2: receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001702 GenerateRuntimeSetProperty(masm);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001703
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001704 // Check whether the elements is a pixel array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001705 // r4: elements map.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001706 __ bind(&check_pixel_array);
1707 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001708 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001709 __ b(ne, &slow);
1710 // Check that the value is a smi. If a conversion is needed call into the
1711 // runtime to convert and clamp.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001712 __ BranchOnNotSmi(value, &slow);
1713 __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the key.
1714 __ ldr(ip, FieldMemOperand(elements, PixelArray::kLengthOffset));
1715 __ cmp(r4, Operand(ip));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001716 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001717 __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +00001718 __ Usat(r5, 8, Operand(r5)); // Clamp the value to [0..255].
1719
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001720 // Get the pointer to the external array. This clobbers elements.
1721 __ ldr(elements,
1722 FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
1723 __ strb(r5, MemOperand(elements, r4)); // Elements is now external array.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001724 __ Ret();
1725
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001726 // Extra capacity case: Check if there is extra capacity to
1727 // perform the store and update the length. Used for adding one
1728 // element to the array by writing to array[array.length].
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001729 __ bind(&extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001730 // Condition code from comparing key and array length is still available.
1731 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1732 // Check for room in the elements backing store.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001733 // Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001734 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001735 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001736 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001737 // Calculate key + 1 as smi.
1738 ASSERT_EQ(0, kSmiTag);
1739 __ add(r4, key, Operand(Smi::FromInt(1)));
1740 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001741 __ b(&fast);
1742
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001743 // Array case: Get the length and the elements array from the JS
1744 // array. Check that the array is in fast mode; if it is the
1745 // length is always a smi.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001746 __ bind(&array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001747 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1748 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001749 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001750 __ cmp(r4, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001751 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001752
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001753 // Check the key against the length in the array.
1754 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1755 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001756 __ b(hs, &extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001757 // Fall through to fast case.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001758
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001759 __ bind(&fast);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001760 // Fast case, store the value to the elements backing store.
1761 __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1762 __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1763 __ str(value, MemOperand(r5));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001764 // Skip write barrier if the written value is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001765 __ tst(value, Operand(kSmiTagMask));
1766 __ Ret(eq);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001767 // Update write barrier for the elements array address.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001768 __ sub(r4, r5, Operand(elements));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001769 __ RecordWrite(elements, Operand(r4), r5, r6);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001770
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001771 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772}
1773
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001774
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001775// Convert int passed in register ival to IEE 754 single precision
1776// floating point value and store it into register fval.
1777// If VFP3 is available use it for conversion.
1778static void ConvertIntToFloat(MacroAssembler* masm,
1779 Register ival,
1780 Register fval,
1781 Register scratch1,
1782 Register scratch2) {
1783 if (CpuFeatures::IsSupported(VFP3)) {
1784 CpuFeatures::Scope scope(VFP3);
1785 __ vmov(s0, ival);
1786 __ vcvt_f32_s32(s0, s0);
1787 __ vmov(fval, s0);
1788 } else {
1789 Label not_special, done;
1790 // Move sign bit from source to destination. This works because the sign
1791 // bit in the exponent word of the double has the same position and polarity
1792 // as the 2's complement sign bit in a Smi.
1793 ASSERT(kBinary32SignMask == 0x80000000u);
1794
1795 __ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
1796 // Negate value if it is negative.
1797 __ rsb(ival, ival, Operand(0), LeaveCC, ne);
1798
1799 // We have -1, 0 or 1, which we treat specially. Register ival contains
1800 // absolute value: it is either equal to 1 (special case of -1 and 1),
1801 // greater than 1 (not a special case) or less than 1 (special case of 0).
1802 __ cmp(ival, Operand(1));
1803 __ b(gt, &not_special);
1804
1805 // For 1 or -1 we need to or in the 0 exponent (biased).
1806 static const uint32_t exponent_word_for_1 =
1807 kBinary32ExponentBias << kBinary32ExponentShift;
1808
1809 __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq);
1810 __ b(&done);
1811
1812 __ bind(&not_special);
1813 // Count leading zeros.
1814 // Gets the wrong answer for 0, but we already checked for that case above.
1815 Register zeros = scratch2;
lrn@chromium.org32d961d2010-06-30 09:09:34 +00001816 __ CountLeadingZeros(zeros, ival, scratch1);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001817
1818 // Compute exponent and or it into the exponent register.
1819 __ rsb(scratch1,
1820 zeros,
1821 Operand((kBitsPerInt - 1) + kBinary32ExponentBias));
1822
1823 __ orr(fval,
1824 fval,
1825 Operand(scratch1, LSL, kBinary32ExponentShift));
1826
1827 // Shift up the source chopping the top bit off.
1828 __ add(zeros, zeros, Operand(1));
1829 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1830 __ mov(ival, Operand(ival, LSL, zeros));
1831 // And the top (top 20 bits).
1832 __ orr(fval,
1833 fval,
1834 Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits));
1835
1836 __ bind(&done);
1837 }
1838}
1839
1840
1841static bool IsElementTypeSigned(ExternalArrayType array_type) {
1842 switch (array_type) {
1843 case kExternalByteArray:
1844 case kExternalShortArray:
1845 case kExternalIntArray:
1846 return true;
1847
1848 case kExternalUnsignedByteArray:
1849 case kExternalUnsignedShortArray:
1850 case kExternalUnsignedIntArray:
1851 return false;
1852
1853 default:
1854 UNREACHABLE();
1855 return false;
1856 }
1857}
1858
1859
ager@chromium.org3811b432009-10-28 14:53:37 +00001860void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
1861 ExternalArrayType array_type) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001862 // ---------- S t a t e --------------
1863 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001864 // -- r1 : key
1865 // -- r2 : receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001866 // -- lr : return address
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001867 // -----------------------------------
1868 Label slow, check_heap_number;
1869
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001870 // Register usage.
1871 Register value = r0;
1872 Register key = r1;
1873 Register receiver = r2;
1874 // r3 mostly holds the elements array or the destination external array.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001875
1876 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001877 __ BranchOnSmi(receiver, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001878
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001879 // Check that the object is a JS object. Load map into r3.
1880 __ CompareObjectType(receiver, r3, r4, FIRST_JS_OBJECT_TYPE);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001881 __ b(le, &slow);
1882
1883 // Check that the receiver does not require access checks. We need
1884 // to do this because this generic stub does not perform map checks.
1885 __ ldrb(ip, FieldMemOperand(r3, Map::kBitFieldOffset));
1886 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1887 __ b(ne, &slow);
1888
1889 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001890 __ BranchOnNotSmi(key, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001891
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001892 // Check that the elements array is the appropriate type of ExternalArray.
1893 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
1894 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001895 __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001896 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001897 __ b(ne, &slow);
1898
1899 // Check that the index is in range.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001900 __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the index.
1901 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
1902 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001903 // Unsigned comparison catches both negative and too-large values.
1904 __ b(hs, &slow);
1905
1906 // Handle both smis and HeapNumbers in the fast path. Go to the
1907 // runtime for all other kinds of values.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001908 // r3: external array.
1909 // r4: key (integer).
1910 __ BranchOnNotSmi(value, &check_heap_number);
1911 __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
1912 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001913
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001914 // r3: base pointer of external storage.
1915 // r4: key (integer).
1916 // r5: value (integer).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001917 switch (array_type) {
1918 case kExternalByteArray:
1919 case kExternalUnsignedByteArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001920 __ strb(r5, MemOperand(r3, r4, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001921 break;
1922 case kExternalShortArray:
1923 case kExternalUnsignedShortArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001924 __ strh(r5, MemOperand(r3, r4, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001925 break;
1926 case kExternalIntArray:
1927 case kExternalUnsignedIntArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001928 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001929 break;
1930 case kExternalFloatArray:
1931 // Need to perform int-to-float conversion.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001932 ConvertIntToFloat(masm, r5, r6, r7, r9);
1933 __ str(r6, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001934 break;
1935 default:
1936 UNREACHABLE();
1937 break;
1938 }
1939
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001940 // Entry registers are intact, r0 holds the value which is the return value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001941 __ Ret();
1942
1943
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001944 // r3: external array.
1945 // r4: index (integer).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001946 __ bind(&check_heap_number);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001947 __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001948 __ b(ne, &slow);
1949
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001950 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
1951
1952 // r3: base pointer of external storage.
1953 // r4: key (integer).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001954
1955 // The WebGL specification leaves the behavior of storing NaN and
1956 // +/-Infinity into integer arrays basically undefined. For more
1957 // reproducible behavior, convert these to zero.
1958 if (CpuFeatures::IsSupported(VFP3)) {
1959 CpuFeatures::Scope scope(VFP3);
1960
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001961
1962 if (array_type == kExternalFloatArray) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001963 // vldr requires offset to be a multiple of 4 so we can not
1964 // include -kHeapObjectTag into it.
1965 __ sub(r5, r0, Operand(kHeapObjectTag));
1966 __ vldr(d0, r5, HeapNumber::kValueOffset);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001967 __ vcvt_f32_f64(s0, d0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001968 __ vmov(r5, s0);
1969 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001970 } else {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001971 // Need to perform float-to-int conversion.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001972 // Test for NaN or infinity (both give zero).
1973 __ ldr(r6, FieldMemOperand(r5, HeapNumber::kExponentOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001974
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001975 // Hoisted load. vldr requires offset to be a multiple of 4 so we can not
1976 // include -kHeapObjectTag into it.
1977 __ sub(r5, r0, Operand(kHeapObjectTag));
1978 __ vldr(d0, r5, HeapNumber::kValueOffset);
1979
1980 __ Sbfx(r6, r6, HeapNumber::kExponentShift, HeapNumber::kExponentBits);
1981 // NaNs and Infinities have all-one exponents so they sign extend to -1.
1982 __ cmp(r6, Operand(-1));
1983 __ mov(r5, Operand(Smi::FromInt(0)), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001984
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001985 // Not infinity or NaN simply convert to int.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001986 if (IsElementTypeSigned(array_type)) {
1987 __ vcvt_s32_f64(s0, d0, ne);
1988 } else {
1989 __ vcvt_u32_f64(s0, d0, ne);
1990 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001991 __ vmov(r5, s0, ne);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001992
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001993 switch (array_type) {
1994 case kExternalByteArray:
1995 case kExternalUnsignedByteArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001996 __ strb(r5, MemOperand(r3, r4, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001997 break;
1998 case kExternalShortArray:
1999 case kExternalUnsignedShortArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002000 __ strh(r5, MemOperand(r3, r4, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002001 break;
2002 case kExternalIntArray:
2003 case kExternalUnsignedIntArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002004 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002005 break;
2006 default:
2007 UNREACHABLE();
2008 break;
2009 }
2010 }
2011
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002012 // Entry registers are intact, r0 holds the value which is the return value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002013 __ Ret();
2014 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002015 // VFP3 is not available do manual conversions.
2016 __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
2017 __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002018
2019 if (array_type == kExternalFloatArray) {
2020 Label done, nan_or_infinity_or_zero;
2021 static const int kMantissaInHiWordShift =
2022 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
2023
2024 static const int kMantissaInLoWordShift =
2025 kBitsPerInt - kMantissaInHiWordShift;
2026
2027 // Test for all special exponent values: zeros, subnormal numbers, NaNs
2028 // and infinities. All these should be converted to 0.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002029 __ mov(r7, Operand(HeapNumber::kExponentMask));
2030 __ and_(r9, r5, Operand(r7), SetCC);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002031 __ b(eq, &nan_or_infinity_or_zero);
2032
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002033 __ teq(r9, Operand(r7));
2034 __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002035 __ b(eq, &nan_or_infinity_or_zero);
2036
2037 // Rebias exponent.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002038 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
2039 __ add(r9,
2040 r9,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002041 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
2042
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002043 __ cmp(r9, Operand(kBinary32MaxExponent));
2044 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
2045 __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002046 __ b(gt, &done);
2047
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002048 __ cmp(r9, Operand(kBinary32MinExponent));
2049 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002050 __ b(lt, &done);
2051
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002052 __ and_(r7, r5, Operand(HeapNumber::kSignMask));
2053 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
2054 __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
2055 __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
2056 __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002057
2058 __ bind(&done);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002059 __ str(r5, MemOperand(r3, r4, LSL, 2));
2060 // Entry registers are intact, r0 holds the value which is the return
2061 // value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002062 __ Ret();
2063
2064 __ bind(&nan_or_infinity_or_zero);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002065 __ and_(r7, r5, Operand(HeapNumber::kSignMask));
2066 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
2067 __ orr(r9, r9, r7);
2068 __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
2069 __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002070 __ b(&done);
2071 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002072 bool is_signed_type = IsElementTypeSigned(array_type);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002073 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002074 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002075
2076 Label done, sign;
2077
2078 // Test for all special exponent values: zeros, subnormal numbers, NaNs
2079 // and infinities. All these should be converted to 0.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002080 __ mov(r7, Operand(HeapNumber::kExponentMask));
2081 __ and_(r9, r5, Operand(r7), SetCC);
2082 __ mov(r5, Operand(0), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002083 __ b(eq, &done);
2084
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002085 __ teq(r9, Operand(r7));
2086 __ mov(r5, Operand(0), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002087 __ b(eq, &done);
2088
2089 // Unbias exponent.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002090 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
2091 __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002092 // If exponent is negative than result is 0.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002093 __ mov(r5, Operand(0), LeaveCC, mi);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002094 __ b(mi, &done);
2095
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002096 // If exponent is too big than result is minimal value.
2097 __ cmp(r9, Operand(meaningfull_bits - 1));
2098 __ mov(r5, Operand(min_value), LeaveCC, ge);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002099 __ b(ge, &done);
2100
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002101 __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
2102 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
2103 __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002104
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002105 __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
2106 __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002107 __ b(pl, &sign);
2108
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002109 __ rsb(r9, r9, Operand(0));
2110 __ mov(r5, Operand(r5, LSL, r9));
2111 __ rsb(r9, r9, Operand(meaningfull_bits));
2112 __ orr(r5, r5, Operand(r6, LSR, r9));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002113
2114 __ bind(&sign);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002115 __ teq(r7, Operand(0));
2116 __ rsb(r5, r5, Operand(0), LeaveCC, ne);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002117
2118 __ bind(&done);
2119 switch (array_type) {
2120 case kExternalByteArray:
2121 case kExternalUnsignedByteArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002122 __ strb(r5, MemOperand(r3, r4, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002123 break;
2124 case kExternalShortArray:
2125 case kExternalUnsignedShortArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002126 __ strh(r5, MemOperand(r3, r4, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002127 break;
2128 case kExternalIntArray:
2129 case kExternalUnsignedIntArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002130 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002131 break;
2132 default:
2133 UNREACHABLE();
2134 break;
2135 }
2136 }
2137 }
2138
2139 // Slow case: call runtime.
2140 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002141
2142 // Entry registers are intact.
2143 // r0: value
2144 // r1: key
2145 // r2: receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002146 GenerateRuntimeSetProperty(masm);
ager@chromium.org3811b432009-10-28 14:53:37 +00002147}
2148
2149
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
2151 // ----------- S t a t e -------------
2152 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00002153 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 // -- r2 : name
2155 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156 // -----------------------------------
2157
2158 // Get the receiver from the stack and probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002159 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
2160 NOT_IN_LOOP,
2161 MONOMORPHIC);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002162 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002163
2164 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002165 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166}
2167
2168
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002169void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002170 // ----------- S t a t e -------------
2171 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00002172 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 // -- r2 : name
2174 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175 // -----------------------------------
2176
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002177 __ Push(r1, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002178
mads.s.ager31e71382008-08-13 09:32:07 +00002179 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002180 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
2181 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182}
2183
2184
ager@chromium.org5c838252010-02-19 08:53:10 +00002185void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
2186 // ----------- S t a t e -------------
2187 // -- r0 : value
2188 // -- r1 : receiver
2189 // -- r2 : name
2190 // -- lr : return address
2191 // -----------------------------------
2192 //
2193 // This accepts as a receiver anything JSObject::SetElementsLength accepts
2194 // (currently anything except for external and pixel arrays which means
2195 // anything with elements of FixedArray type.), but currently is restricted
2196 // to JSArray.
2197 // Value must be a number, but only smis are accepted as the most common case.
2198
2199 Label miss;
2200
2201 Register receiver = r1;
2202 Register value = r0;
2203 Register scratch = r3;
2204
2205 // Check that the receiver isn't a smi.
2206 __ BranchOnSmi(receiver, &miss);
2207
2208 // Check that the object is a JS array.
2209 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
2210 __ b(ne, &miss);
2211
2212 // Check that elements are FixedArray.
2213 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
2214 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
2215 __ b(ne, &miss);
2216
2217 // Check that value is a smi.
2218 __ BranchOnNotSmi(value, &miss);
2219
2220 // Prepare tail call to StoreIC_ArrayLength.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002221 __ Push(receiver, value);
ager@chromium.org5c838252010-02-19 08:53:10 +00002222
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002223 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
2224 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002225
2226 __ bind(&miss);
2227
2228 GenerateMiss(masm);
2229}
2230
2231
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002232void StoreIC::GenerateNormal(MacroAssembler* masm) {
2233 // ----------- S t a t e -------------
2234 // -- r0 : value
2235 // -- r1 : receiver
2236 // -- r2 : name
2237 // -- lr : return address
2238 // -----------------------------------
2239 Label miss;
2240
2241 GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
2242
2243 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
2244 __ IncrementCounter(&Counters::store_normal_hit, 1, r4, r5);
2245 __ Ret();
2246
2247 __ bind(&miss);
2248 __ IncrementCounter(&Counters::store_normal_miss, 1, r4, r5);
2249 GenerateMiss(masm);
2250}
2251
2252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253#undef __
2254
2255
2256} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002257
2258#endif // V8_TARGET_ARCH_ARM