blob: a7c436d61b3353d07e74febc5827f11835fb6211 [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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050// Helper function used from LoadIC/CallIC GenerateNormal.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000051// receiver: Receiver. It is not clobbered if a jump to the miss label is
52// done
53// name: Property name. It is not clobbered if a jump to the miss label is
54// done
55// result: Register for the result. It is only updated if a jump to the miss
56// label is not done. Can be the same as receiver or name clobbering
57// one of these in the case of not jumping to the miss label.
58// The three scratch registers need to be different from the receiver, name and
59// result.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060static void GenerateDictionaryLoad(MacroAssembler* masm,
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000061 Label* miss,
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000062 Register receiver,
63 Register name,
64 Register result,
65 Register scratch1,
66 Register scratch2,
67 Register scratch3,
68 DictionaryCheck check_dictionary) {
69 // Main use of the scratch registers.
70 // scratch1: Used to hold the property dictionary.
71 // scratch2: Used as temporary and to hold the capacity of the property
72 // dictionary.
73 // scratch3: Used as temporary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000075 Label done;
76
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 // Check for the absence of an interceptor.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000078 // Load the map into scratch1.
79 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kMapOffset));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +000080
81 // Bail out if the receiver has a named interceptor.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000082 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
83 __ tst(scratch2, Operand(1 << Map::kHasNamedInterceptor));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +000084 __ b(nz, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000085
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000086 // Bail out if we have a JS global proxy object.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000087 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
88 __ cmp(scratch2, Operand(JS_GLOBAL_PROXY_TYPE));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000089 __ b(eq, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000090
kasperl@chromium.orge959c182009-07-27 08:59:04 +000091 // Possible work-around for http://crbug.com/16276.
92 // See also: http://codereview.chromium.org/155418.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000093 __ cmp(scratch2, Operand(JS_GLOBAL_OBJECT_TYPE));
kasperl@chromium.orge959c182009-07-27 08:59:04 +000094 __ b(eq, miss);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000095 __ cmp(scratch2, Operand(JS_BUILTINS_OBJECT_TYPE));
kasperl@chromium.orge959c182009-07-27 08:59:04 +000096 __ b(eq, miss);
97
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +000098 // Load the properties array.
99 __ ldr(scratch1, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
100
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 // Check that the properties array is a dictionary.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000102 if (check_dictionary == CHECK_DICTIONARY) {
103 __ ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
104 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
105 __ cmp(scratch2, ip);
106 __ b(ne, miss);
107 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
109 // Compute the capacity mask.
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000110 const int kCapacityOffset = StringDictionary::kHeaderSize +
111 StringDictionary::kCapacityIndex * kPointerSize;
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000112 __ ldr(scratch2, FieldMemOperand(scratch1, kCapacityOffset));
113 __ mov(scratch2, Operand(scratch2, ASR, kSmiTagSize)); // convert smi to int
114 __ sub(scratch2, scratch2, Operand(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000116 const int kElementsStartOffset = StringDictionary::kHeaderSize +
117 StringDictionary::kElementsStartIndex * kPointerSize;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118
119 // Generate an unrolled loop that performs a few probes before
120 // giving up. Measurements done on Gmail indicate that 2 probes
121 // cover ~93% of loads from dictionaries.
122 static const int kProbes = 4;
123 for (int i = 0; i < kProbes; i++) {
124 // Compute the masked index: (hash + i + i * i) & mask.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000125 __ ldr(scratch3, FieldMemOperand(name, String::kHashFieldOffset));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000126 if (i > 0) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000127 // Add the probe offset (i + i * i) left shifted to avoid right shifting
128 // the hash in a separate instruction. The value hash + i + i * i is right
129 // shifted in the following and instruction.
130 ASSERT(StringDictionary::GetProbeOffset(i) <
131 1 << (32 - String::kHashFieldOffset));
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000132 __ add(scratch3, scratch3, Operand(
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000133 StringDictionary::GetProbeOffset(i) << String::kHashShift));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000134 }
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000135 __ and_(scratch3, scratch2, Operand(scratch3, LSR, String::kHashShift));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136
137 // Scale the index by multiplying by the element size.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000138 ASSERT(StringDictionary::kEntrySize == 3);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000139 // scratch3 = scratch3 * 3.
140 __ add(scratch3, scratch3, Operand(scratch3, LSL, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141
142 // Check if the key is identical to the name.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000143 __ add(scratch3, scratch1, Operand(scratch3, LSL, 2));
144 __ ldr(ip, FieldMemOperand(scratch3, kElementsStartOffset));
145 __ cmp(name, Operand(ip));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 if (i != kProbes - 1) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000147 __ b(eq, &done);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000148 } else {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000149 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150 }
151 }
152
153 // Check that the value is a normal property.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000154 __ bind(&done); // scratch3 == scratch1 + 4 * index
155 __ ldr(scratch2,
156 FieldMemOperand(scratch3, kElementsStartOffset + 2 * kPointerSize));
157 __ tst(scratch2, Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000158 __ b(ne, miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159
160 // Get the value at the masked, scaled index and return.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000161 __ ldr(result,
162 FieldMemOperand(scratch3, kElementsStartOffset + 1 * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000163}
164
165
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000166static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
167 Label* miss,
168 Register elements,
169 Register key,
170 Register t0,
171 Register t1,
172 Register t2) {
173 // Register use:
174 //
175 // elements - holds the slow-case elements of the receiver and is unchanged.
176 //
177 // key - holds the smi key on entry and is unchanged if a branch is
178 // performed to the miss label.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000179 // Holds the result on exit if the load succeeded.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000180 //
181 // Scratch registers:
182 //
183 // t0 - holds the untagged key on entry and holds the hash once computed.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000184 //
185 // t1 - used to hold the capacity mask of the dictionary
186 //
187 // t2 - used for the index into the dictionary.
188 Label done;
189
190 // Compute the hash code from the untagged key. This must be kept in sync
191 // with ComputeIntegerHash in utils.h.
192 //
193 // hash = ~hash + (hash << 15);
194 __ mvn(t1, Operand(t0));
195 __ add(t0, t1, Operand(t0, LSL, 15));
196 // hash = hash ^ (hash >> 12);
197 __ eor(t0, t0, Operand(t0, LSR, 12));
198 // hash = hash + (hash << 2);
199 __ add(t0, t0, Operand(t0, LSL, 2));
200 // hash = hash ^ (hash >> 4);
201 __ eor(t0, t0, Operand(t0, LSR, 4));
202 // hash = hash * 2057;
203 __ mov(t1, Operand(2057));
204 __ mul(t0, t0, t1);
205 // hash = hash ^ (hash >> 16);
206 __ eor(t0, t0, Operand(t0, LSR, 16));
207
208 // Compute the capacity mask.
209 __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
210 __ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int
211 __ sub(t1, t1, Operand(1));
212
213 // Generate an unrolled loop that performs a few probes before giving up.
214 static const int kProbes = 4;
215 for (int i = 0; i < kProbes; i++) {
216 // Use t2 for index calculations and keep the hash intact in t0.
217 __ mov(t2, t0);
218 // Compute the masked index: (hash + i + i * i) & mask.
219 if (i > 0) {
220 __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i)));
221 }
222 __ and_(t2, t2, Operand(t1));
223
224 // Scale the index by multiplying by the element size.
225 ASSERT(NumberDictionary::kEntrySize == 3);
226 __ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3
227
228 // Check if the key is identical to the name.
229 __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2));
230 __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset));
231 __ cmp(key, Operand(ip));
232 if (i != kProbes - 1) {
233 __ b(eq, &done);
234 } else {
235 __ b(ne, miss);
236 }
237 }
238
239 __ bind(&done);
240 // Check that the value is a normal property.
241 // t2: elements + (index * kPointerSize)
242 const int kDetailsOffset =
243 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
244 __ ldr(t1, FieldMemOperand(t2, kDetailsOffset));
245 __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
246 __ b(ne, miss);
247
248 // Get the value at the masked, scaled index and return.
249 const int kValueOffset =
250 NumberDictionary::kElementsStartOffset + kPointerSize;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000251 __ ldr(key, FieldMemOperand(t2, kValueOffset));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000252}
253
254
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
256 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 // -- r2 : name
258 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000259 // -- r0 : receiver
260 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261 // -----------------------------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262 Label miss;
263
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000264 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000266 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267}
268
269
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000270void LoadIC::GenerateStringLength(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000271 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000272 // -- r2 : name
273 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000274 // -- r0 : receiver
275 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000276 // -----------------------------------
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000277 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278
ager@chromium.org5c838252010-02-19 08:53:10 +0000279 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000280 // Cache miss: Jump to runtime.
281 __ bind(&miss);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000282 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283}
284
285
286void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
287 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 // -- r2 : name
289 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000290 // -- r0 : receiver
291 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000292 // -----------------------------------
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000293 Label miss;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000294
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +0000295 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
296 __ bind(&miss);
297 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298}
299
300
301// Defined in ic.cc.
302Object* CallIC_Miss(Arguments args);
303
304void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
305 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000306 // -- r2 : name
307 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000308 // -----------------------------------
309 Label number, non_number, non_string, boolean, probe, miss;
310
mads.s.ager31e71382008-08-13 09:32:07 +0000311 // Get the receiver of the function from the stack into r1.
312 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313
314 // Probe the stub cache.
315 Code::Flags flags =
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000316 Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000317 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000318
319 // If the stub cache probing failed, the receiver might be a value.
320 // For value objects, we use the map of the prototype objects for
321 // the corresponding JSValue for the cache and that is what we need
322 // to probe.
323 //
324 // Check for number.
325 __ tst(r1, Operand(kSmiTagMask));
326 __ b(eq, &number);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000327 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000328 __ b(ne, &non_number);
329 __ bind(&number);
330 StubCompiler::GenerateLoadGlobalFunctionPrototype(
331 masm, Context::NUMBER_FUNCTION_INDEX, r1);
332 __ b(&probe);
333
334 // Check for string.
335 __ bind(&non_number);
336 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
337 __ b(hs, &non_string);
338 StubCompiler::GenerateLoadGlobalFunctionPrototype(
339 masm, Context::STRING_FUNCTION_INDEX, r1);
340 __ b(&probe);
341
342 // Check for boolean.
343 __ bind(&non_string);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000344 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
345 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 __ b(eq, &boolean);
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000347 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
348 __ cmp(r1, ip);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 __ b(ne, &miss);
350 __ bind(&boolean);
351 StubCompiler::GenerateLoadGlobalFunctionPrototype(
352 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
353
354 // Probe the stub cache for the value object.
355 __ bind(&probe);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000356 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357
358 // Cache miss: Jump to runtime.
359 __ bind(&miss);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000360 GenerateMiss(masm, argc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361}
362
363
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000364static void GenerateNormalHelper(MacroAssembler* masm,
365 int argc,
366 bool is_global_object,
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000367 Label* miss,
368 Register scratch) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000369 // Search dictionary - put result in register r1.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000370 GenerateDictionaryLoad(masm, miss, r1, r2, r1, r0, r3, r4, CHECK_DICTIONARY);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000371
372 // Check that the value isn't a smi.
373 __ tst(r1, Operand(kSmiTagMask));
374 __ b(eq, miss);
375
376 // Check that the value is a JSFunction.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000377 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000378 __ b(ne, miss);
379
380 // Patch the receiver with the global proxy if necessary.
381 if (is_global_object) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000382 __ ldr(r0, MemOperand(sp, argc * kPointerSize));
383 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
384 __ str(r0, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000385 }
386
387 // Invoke the function.
388 ParameterCount actual(argc);
389 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
390}
391
392
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000393void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
394 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000395 // -- r2 : name
396 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000398 Label miss, global_object, non_global_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000399
mads.s.ager31e71382008-08-13 09:32:07 +0000400 // Get the receiver of the function from the stack into r1.
401 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000402
403 // Check that the receiver isn't a smi.
404 __ tst(r1, Operand(kSmiTagMask));
405 __ b(eq, &miss);
406
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000407 // Check that the receiver is a valid JS object. Put the map in r3.
408 __ CompareObjectType(r1, r3, r0, FIRST_JS_OBJECT_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 __ b(lt, &miss);
410
411 // If this assert fails, we have to check upper bound too.
412 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
413
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000414 // Check for access to global object.
415 __ cmp(r0, Operand(JS_GLOBAL_OBJECT_TYPE));
416 __ b(eq, &global_object);
417 __ cmp(r0, Operand(JS_BUILTINS_OBJECT_TYPE));
418 __ b(ne, &non_global_object);
419
420 // Accessing global object: Load and invoke.
421 __ bind(&global_object);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000422 // Check that the global object does not require access checks.
423 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
424 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
425 __ b(ne, &miss);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000426 GenerateNormalHelper(masm, argc, true, &miss, r4);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000427
428 // Accessing non-global object: Check for access to global proxy.
429 Label global_proxy, invoke;
430 __ bind(&non_global_object);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000431 __ cmp(r0, Operand(JS_GLOBAL_PROXY_TYPE));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000432 __ b(eq, &global_proxy);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000433 // Check that the non-global, non-global-proxy object does not
434 // require access checks.
435 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
436 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
437 __ b(ne, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000438 __ bind(&invoke);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000439 GenerateNormalHelper(masm, argc, false, &miss, r4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440
441 // Global object access: Check access rights.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000442 __ bind(&global_proxy);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000443 __ CheckAccessGlobalProxy(r1, r0, &miss);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000444 __ b(&invoke);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000446 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447 __ bind(&miss);
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000448 GenerateMiss(masm, argc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449}
450
451
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000452void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 // ----------- S t a t e -------------
ager@chromium.org5c838252010-02-19 08:53:10 +0000454 // -- r2 : name
455 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 // -----------------------------------
457
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000458 // Get the receiver of the function from the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000460
461 __ EnterInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000462
463 // Push the receiver and the name of the function.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000464 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000465
466 // Call the entry.
mads.s.ager31e71382008-08-13 09:32:07 +0000467 __ mov(r0, Operand(2));
sgjesse@chromium.org846fb742009-12-18 08:56:33 +0000468 __ mov(r1, Operand(ExternalReference(IC_Utility(kCallIC_Miss))));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000469
ager@chromium.orga1645e22009-09-09 19:27:10 +0000470 CEntryStub stub(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 __ CallStub(&stub);
472
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000473 // Move result to r1 and leave the internal frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474 __ mov(r1, Operand(r0));
ager@chromium.org236ad962008-09-25 09:45:57 +0000475 __ LeaveInternalFrame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000476
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000477 // Check if the receiver is a global object of some sort.
478 Label invoke, global;
479 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
480 __ tst(r2, Operand(kSmiTagMask));
481 __ b(eq, &invoke);
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000482 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000483 __ b(eq, &global);
484 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
485 __ b(ne, &invoke);
486
487 // Patch the receiver on the stack.
488 __ bind(&global);
489 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
490 __ str(r2, MemOperand(sp, argc * kPointerSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000492 // Invoke the function.
493 ParameterCount actual(argc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000494 __ bind(&invoke);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +0000495 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496}
497
498
499// Defined in ic.cc.
500Object* LoadIC_Miss(Arguments args);
501
502void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
503 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504 // -- r2 : name
505 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000506 // -- r0 : receiver
507 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 // -----------------------------------
509
510 // Probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000511 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
512 NOT_IN_LOOP,
513 MONOMORPHIC);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000514 StubCache::GenerateProbe(masm, flags, r0, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515
516 // Cache miss: Jump to runtime.
ager@chromium.org5c838252010-02-19 08:53:10 +0000517 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518}
519
520
521void LoadIC::GenerateNormal(MacroAssembler* masm) {
522 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523 // -- r2 : name
524 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000525 // -- r0 : receiver
526 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 // -----------------------------------
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000528 Label miss, probe, global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000529
530 // Check that the receiver isn't a smi.
531 __ tst(r0, Operand(kSmiTagMask));
532 __ b(eq, &miss);
533
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000534 // Check that the receiver is a valid JS object. Put the map in r3.
535 __ CompareObjectType(r0, r3, r1, FIRST_JS_OBJECT_TYPE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536 __ b(lt, &miss);
537 // If this assert fails, we have to check upper bound too.
538 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
539
540 // Check for access to global object (unlikely).
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000541 __ cmp(r1, Operand(JS_GLOBAL_PROXY_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 __ b(eq, &global);
543
ager@chromium.org8bb60582008-12-11 12:02:20 +0000544 // Check for non-global object that requires access check.
545 __ ldrb(r3, FieldMemOperand(r3, Map::kBitFieldOffset));
546 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
547 __ b(ne, &miss);
548
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 __ bind(&probe);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000550 GenerateDictionaryLoad(masm, &miss, r0, r2, r0, r1, r3, r4, CHECK_DICTIONARY);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 __ Ret();
552
553 // Global object access: Check access rights.
554 __ bind(&global);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000555 __ CheckAccessGlobalProxy(r0, r1, &miss);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000556 __ b(&probe);
557
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000558 // Cache miss: Jump to runtime.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 __ bind(&miss);
ager@chromium.org5c838252010-02-19 08:53:10 +0000560 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561}
562
563
564void LoadIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000565 // ----------- S t a t e -------------
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 // -- r2 : name
567 // -- lr : return address
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000568 // -- r0 : receiver
569 // -- sp[0] : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 // -----------------------------------
571
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000572 __ mov(r3, r0);
573 __ Push(r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574
mads.s.ager31e71382008-08-13 09:32:07 +0000575 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000576 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss));
577 __ TailCallExternalReference(ref, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000578}
579
580
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000581static inline bool IsInlinedICSite(Address address,
582 Address* inline_end_address) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000583 // If the instruction after the call site is not the pseudo instruction nop1
584 // then this is not related to an inlined in-object property load. The nop1
585 // instruction is located just after the call to the IC in the deferred code
586 // handling the miss in the inlined code. After the nop1 instruction there is
587 // a branch instruction for jumping back from the deferred code.
588 Address address_after_call = address + Assembler::kCallTargetAddressOffset;
589 Instr instr_after_call = Assembler::instr_at(address_after_call);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000590 if (!Assembler::IsNop(instr_after_call, PROPERTY_ACCESS_INLINED)) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000591 return false;
592 }
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000593 Address address_after_nop = address_after_call + Assembler::kInstrSize;
594 Instr instr_after_nop = Assembler::instr_at(address_after_nop);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000595 // There may be some reg-reg move and frame merging code to skip over before
596 // the branch back from the DeferredReferenceGetKeyedValue code to the inlined
597 // code.
598 while (!Assembler::IsBranch(instr_after_nop)) {
599 address_after_nop += Assembler::kInstrSize;
600 instr_after_nop = Assembler::instr_at(address_after_nop);
601 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000602
603 // Find the end of the inlined code for handling the load.
604 int b_offset =
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000605 Assembler::GetBranchOffset(instr_after_nop) + Assembler::kPcLoadDelta;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000606 ASSERT(b_offset < 0); // Jumping back from deferred code.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000607 *inline_end_address = address_after_nop + b_offset;
608
609 return true;
610}
611
612
613void LoadIC::ClearInlinedVersion(Address address) {
614 // Reset the map check of the inlined in-object property load (if present) to
615 // guarantee failure by holding an invalid map (the null value). The offset
616 // can be patched to anything.
617 PatchInlinedLoad(address, Heap::null_value(), 0);
618}
619
620
621bool LoadIC::PatchInlinedLoad(Address address, Object* map, int offset) {
622 // Find the end of the inlined code for handling the load if this is an
623 // inlined IC call site.
624 Address inline_end_address;
625 if (!IsInlinedICSite(address, &inline_end_address)) return false;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000626
627 // Patch the offset of the property load instruction (ldr r0, [r1, #+XXX]).
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000628 // The immediate must be representable in 12 bits.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000629 ASSERT((JSObject::kMaxInstanceSize - JSObject::kHeaderSize) < (1 << 12));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000630 Address ldr_property_instr_address =
631 inline_end_address - Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000632 ASSERT(Assembler::IsLdrRegisterImmediate(
633 Assembler::instr_at(ldr_property_instr_address)));
634 Instr ldr_property_instr = Assembler::instr_at(ldr_property_instr_address);
635 ldr_property_instr = Assembler::SetLdrRegisterImmediateOffset(
636 ldr_property_instr, offset - kHeapObjectTag);
637 Assembler::instr_at_put(ldr_property_instr_address, ldr_property_instr);
638
639 // Indicate that code has changed.
640 CPU::FlushICache(ldr_property_instr_address, 1 * Assembler::kInstrSize);
641
642 // Patch the map check.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000643 Address ldr_map_instr_address =
644 inline_end_address - 4 * Assembler::kInstrSize;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000645 Assembler::set_target_address_at(ldr_map_instr_address,
646 reinterpret_cast<Address>(map));
647 return true;
648}
649
650
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000651void KeyedLoadIC::ClearInlinedVersion(Address address) {
652 // Reset the map check of the inlined keyed load (if present) to
653 // guarantee failure by holding an invalid map (the null value).
654 PatchInlinedLoad(address, Heap::null_value());
ager@chromium.org5ec48922009-05-05 07:25:34 +0000655}
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000656
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000657
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000658bool KeyedLoadIC::PatchInlinedLoad(Address address, Object* map) {
659 Address inline_end_address;
660 if (!IsInlinedICSite(address, &inline_end_address)) return false;
661
662 // Patch the map check.
663 Address ldr_map_instr_address =
vegorov@chromium.orgdff694e2010-05-17 09:10:26 +0000664 inline_end_address -
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000665 (CodeGenerator::kInlinedKeyedLoadInstructionsAfterPatch *
666 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000667 Assembler::set_target_address_at(ldr_map_instr_address,
668 reinterpret_cast<Address>(map));
669 return true;
670}
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000671
672
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000673void KeyedStoreIC::ClearInlinedVersion(Address address) {
674 // Insert null as the elements map to check for. This will make
675 // sure that the elements fast-case map check fails so that control
676 // flows to the IC instead of the inlined version.
677 PatchInlinedStore(address, Heap::null_value());
678}
679
680
681void KeyedStoreIC::RestoreInlinedVersion(Address address) {
682 // Restore the fast-case elements map check so that the inlined
683 // version can be used again.
684 PatchInlinedStore(address, Heap::fixed_array_map());
685}
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000686
687
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000688bool KeyedStoreIC::PatchInlinedStore(Address address, Object* map) {
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000689 // Find the end of the inlined code for handling the store if this is an
690 // inlined IC call site.
691 Address inline_end_address;
692 if (!IsInlinedICSite(address, &inline_end_address)) return false;
693
694 // Patch the map check.
695 Address ldr_map_instr_address =
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000696 inline_end_address -
697 (CodeGenerator::kInlinedKeyedStoreInstructionsAfterPatch *
698 Assembler::kInstrSize);
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000699 Assembler::set_target_address_at(ldr_map_instr_address,
700 reinterpret_cast<Address>(map));
701 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000702}
703
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000704
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000705Object* KeyedLoadIC_Miss(Arguments args);
706
707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000709 // ---------- S t a t e --------------
710 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000711 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000712 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000713 // -----------------------------------
714
ager@chromium.orgac091b72010-05-05 07:34:42 +0000715 __ Push(r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000716
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000717 ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
718 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000719}
720
721
722void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
723 // ---------- S t a t e --------------
724 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000725 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000726 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +0000727 // -----------------------------------
728
ager@chromium.orgac091b72010-05-05 07:34:42 +0000729 __ Push(r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000730
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000731 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000732}
733
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000736 // ---------- S t a t e --------------
737 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +0000738 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000739 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000740 // -----------------------------------
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000741 Label slow, check_string, index_smi, index_string;
742 Label check_pixel_array, probe_dictionary, check_number_dictionary;
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000743
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000744 Register key = r0;
745 Register receiver = r1;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000746
ager@chromium.org5c838252010-02-19 08:53:10 +0000747 // Check that the object isn't a smi.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000748 __ BranchOnSmi(receiver, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000749 // Get the map of the receiver.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000750 __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000751 // Check bit field.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000752 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
kasperl@chromium.orgeac059f2010-01-25 11:02:06 +0000753 __ tst(r3, Operand(kSlowCaseBitFieldMask));
ager@chromium.org8bb60582008-12-11 12:02:20 +0000754 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000755 // Check that the object is some kind of JS object EXCEPT JS Value type.
756 // In the case that the object is a value-wrapper object,
757 // we enter the runtime system to make sure that indexing into string
758 // objects work as intended.
759 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000760 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
761 __ cmp(r2, Operand(JS_OBJECT_TYPE));
762 __ b(lt, &slow);
763
ager@chromium.org5c838252010-02-19 08:53:10 +0000764 // Check that the key is a smi.
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000765 __ BranchOnNotSmi(key, &check_string);
766 __ bind(&index_smi);
767 // Now the key is known to be a smi. This place is also jumped to from below
768 // where a numeric string is converted to a smi.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000769 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000770 // Check that the object is in fast mode (not dictionary).
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000771 __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +0000772 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
773 __ cmp(r3, ip);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000774 __ b(ne, &check_pixel_array);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000775 // Check that the key (index) is within bounds.
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000776 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset));
777 __ cmp(key, Operand(r3));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000778 __ b(hs, &slow);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000779 // Fast case: Do the load.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000780 __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000781 // The key is a smi.
782 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
783 __ ldr(r2, MemOperand(r3, key, LSL, kPointerSizeLog2 - kSmiTagSize));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000784 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000785 __ cmp(r2, ip);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000786 // In case the loaded value is the_hole we have to consult GetProperty
787 // to ensure the prototype chain is searched.
788 __ b(eq, &slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000789 __ mov(r0, r2);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000790 __ IncrementCounter(&Counters::keyed_load_generic_smi, 1, r2, r3);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000791 __ Ret();
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000792
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000793 // Check whether the elements is a pixel array.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000794 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000795 // r3: elements map
796 // r4: elements
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000797 __ bind(&check_pixel_array);
798 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
799 __ cmp(r3, ip);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000800 __ b(ne, &check_number_dictionary);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000801 __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000802 __ mov(r2, Operand(key, ASR, kSmiTagSize));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000803 __ cmp(r2, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000804 __ b(hs, &slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000805 __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset));
806 __ ldrb(r2, MemOperand(ip, r2));
807 __ mov(r0, Operand(r2, LSL, kSmiTagSize)); // Tag result as smi.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000808 __ Ret();
809
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000810 __ bind(&check_number_dictionary);
811 // Check whether the elements is a number dictionary.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000812 // r0: key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000813 // r3: elements map
814 // r4: elements
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000815 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
816 __ cmp(r3, ip);
817 __ b(ne, &slow);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000818 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000819 GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000820 __ Ret();
821
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000822 // Slow case, key and receiver still in r0 and r1.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000823 __ bind(&slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000824 __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
ager@chromium.org5c838252010-02-19 08:53:10 +0000825 GenerateRuntimeGetProperty(masm);
sgjesse@chromium.org82dbbab2010-06-02 08:57:44 +0000826
827 __ bind(&check_string);
828 // The key is not a smi.
829 // Is it a string?
830 // r0: key
831 // r1: receiver
832 __ CompareObjectType(r0, r2, r3, FIRST_NONSTRING_TYPE);
833 __ b(ge, &slow);
834
835 // Is the string an array index, with cached numeric value?
836 __ ldr(r3, FieldMemOperand(r0, String::kHashFieldOffset));
837 __ tst(r3, Operand(String::kIsArrayIndexMask));
838 __ b(ne, &index_string);
839
840 // Is the string a symbol?
841 // r2: key map
842 __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceTypeOffset));
843 ASSERT(kSymbolTag != 0);
844 __ tst(r3, Operand(kIsSymbolMask));
845 __ b(eq, &slow);
846
847 // If the receiver is a fast-case object, check the keyed lookup
848 // cache. Otherwise probe the dictionary.
849 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
850 __ ldr(r3, FieldMemOperand(r3, HeapObject::kMapOffset));
851 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
852 __ cmp(r3, ip);
853 __ b(eq, &probe_dictionary);
854
855 // Load the map of the receiver, compute the keyed lookup cache hash
856 // based on 32 bits of the map pointer and the string hash.
857 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
858 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
859 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
860 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
861 __ and_(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
862
863 // Load the key (consisting of map and symbol) from the cache and
864 // check for match.
865 ExternalReference cache_keys = ExternalReference::keyed_lookup_cache_keys();
866 __ mov(r4, Operand(cache_keys));
867 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
868 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
869 __ cmp(r2, r5);
870 __ b(ne, &slow);
871 __ ldr(r5, MemOperand(r4));
872 __ cmp(r0, r5);
873 __ b(ne, &slow);
874
875 // Get field offset and check that it is an in-object property.
876 // r0 : key
877 // r1 : receiver
878 // r2 : receiver's map
879 // r3 : lookup cache index
880 ExternalReference cache_field_offsets
881 = ExternalReference::keyed_lookup_cache_field_offsets();
882 __ mov(r4, Operand(cache_field_offsets));
883 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
884 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
885 __ cmp(r5, r6);
886 __ b(ge, &slow);
887
888 // Load in-object property.
889 __ sub(r5, r5, r6); // Index from end of object.
890 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
891 __ add(r6, r6, r5); // Index from start of object.
892 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
893 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
894 __ IncrementCounter(&Counters::keyed_load_generic_lookup_cache, 1, r2, r3);
895 __ Ret();
896
897 // Do a quick inline probe of the receiver's dictionary, if it
898 // exists.
899 __ bind(&probe_dictionary);
900 // Load the property to r0.
901 GenerateDictionaryLoad(
902 masm, &slow, r1, r0, r0, r2, r3, r4, DICTIONARY_CHECK_DONE);
903 __ IncrementCounter(&Counters::keyed_load_generic_symbol, 1, r2, r3);
904 __ Ret();
905
906 __ b(&slow);
907 // If the hash field contains an array index pick it out. The assert checks
908 // that the constants for the maximum number of digits for an array index
909 // cached in the hash field and the number of bits reserved for it does not
910 // conflict.
911 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
912 (1 << String::kArrayIndexValueBits));
913 __ bind(&index_string);
914 // r0: key (string)
915 // r1: receiver
916 // r3: hash field
917 // We want the smi-tagged index in r0. kArrayIndexValueMask has zeros in
918 // the low kHashShift bits.
919 ASSERT(String::kHashShift >= kSmiTagSize);
920 __ and_(r3, r3, Operand(String::kArrayIndexValueMask));
921 // Here we actually clobber the key (r0) which will be used if calling into
922 // runtime later. However as the new key is the numeric value of a string key
923 // there is no difference in using either key.
924 __ mov(r0, Operand(r3, ASR, String::kHashShift - kSmiTagSize));
925 // Now jump to the place where smi keys are handled.
926 __ jmp(&index_smi);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927}
928
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000929
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000930void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
931 // ---------- S t a t e --------------
932 // -- lr : return address
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000933 // -- r0 : key (index)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000934 // -- r1 : receiver
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000935 // -----------------------------------
ager@chromium.orgac091b72010-05-05 07:34:42 +0000936 Label miss;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000937 Label index_out_of_range;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000938
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000939 Register receiver = r1;
ager@chromium.orgac091b72010-05-05 07:34:42 +0000940 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000941 Register scratch1 = r2;
942 Register scratch2 = r3;
943 Register result = r0;
ager@chromium.org357bf652010-04-12 11:30:10 +0000944
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000945 StringCharAtGenerator char_at_generator(receiver,
946 index,
947 scratch1,
948 scratch2,
949 result,
950 &miss, // When not a string.
951 &miss, // When not a number.
952 &index_out_of_range,
953 STRING_INDEX_IS_ARRAY_INDEX);
954 char_at_generator.GenerateFast(masm);
955 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +0000956
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000957 ICRuntimeCallHelper call_helper;
958 char_at_generator.GenerateSlow(masm, call_helper);
ager@chromium.org357bf652010-04-12 11:30:10 +0000959
ager@chromium.orgac091b72010-05-05 07:34:42 +0000960 __ bind(&index_out_of_range);
961 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
962 __ Ret();
ager@chromium.org357bf652010-04-12 11:30:10 +0000963
964 __ bind(&miss);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000965 GenerateMiss(masm);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000966}
967
968
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000969// Convert unsigned integer with specified number of leading zeroes in binary
970// representation to IEEE 754 double.
971// Integer to convert is passed in register hiword.
972// Resulting double is returned in registers hiword:loword.
973// This functions does not work correctly for 0.
974static void GenerateUInt2Double(MacroAssembler* masm,
975 Register hiword,
976 Register loword,
977 Register scratch,
978 int leading_zeroes) {
979 const int meaningful_bits = kBitsPerInt - leading_zeroes - 1;
980 const int biased_exponent = HeapNumber::kExponentBias + meaningful_bits;
981
982 const int mantissa_shift_for_hi_word =
983 meaningful_bits - HeapNumber::kMantissaBitsInTopWord;
984
985 const int mantissa_shift_for_lo_word =
986 kBitsPerInt - mantissa_shift_for_hi_word;
987
988 __ mov(scratch, Operand(biased_exponent << HeapNumber::kExponentShift));
989 if (mantissa_shift_for_hi_word > 0) {
990 __ mov(loword, Operand(hiword, LSL, mantissa_shift_for_lo_word));
991 __ orr(hiword, scratch, Operand(hiword, LSR, mantissa_shift_for_hi_word));
992 } else {
993 __ mov(loword, Operand(0));
994 __ orr(hiword, scratch, Operand(hiword, LSL, mantissa_shift_for_hi_word));
995 }
996
997 // If least significant bit of biased exponent was not 1 it was corrupted
998 // by most significant bit of mantissa so we should fix that.
999 if (!(biased_exponent & 1)) {
1000 __ bic(hiword, hiword, Operand(1 << HeapNumber::kExponentShift));
1001 }
1002}
1003
1004
ager@chromium.org3811b432009-10-28 14:53:37 +00001005void KeyedLoadIC::GenerateExternalArray(MacroAssembler* masm,
1006 ExternalArrayType array_type) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001007 // ---------- S t a t e --------------
1008 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001009 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001010 // -- r1 : receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001011 // -----------------------------------
1012 Label slow, failed_allocation;
1013
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001014 Register key = r0;
1015 Register receiver = r1;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001016
1017 // Check that the object isn't a smi
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001018 __ BranchOnSmi(receiver, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001019
1020 // Check that the key is a smi.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001021 __ BranchOnNotSmi(key, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001022
1023 // Check that the object is a JS object. Load map into r2.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001024 __ CompareObjectType(receiver, r2, r3, FIRST_JS_OBJECT_TYPE);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001025 __ b(lt, &slow);
1026
1027 // Check that the receiver does not require access checks. We need
1028 // to check this explicitly since this generic stub does not perform
1029 // map checks.
1030 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1031 __ tst(r3, Operand(1 << Map::kIsAccessCheckNeeded));
1032 __ b(ne, &slow);
1033
1034 // Check that the elements array is the appropriate type of
1035 // ExternalArray.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001036 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
1037 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001038 __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
1039 __ cmp(r2, ip);
1040 __ b(ne, &slow);
1041
1042 // Check that the index is in range.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001043 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
1044 __ cmp(ip, Operand(key, ASR, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001045 // Unsigned comparison catches both negative and too-large values.
1046 __ b(lo, &slow);
1047
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001048 // r3: elements array
1049 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
1050 // r3: base pointer of external storage
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001051
1052 // We are not untagging smi key and instead work with it
1053 // as if it was premultiplied by 2.
1054 ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
1055
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001056 Register value = r2;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001057 switch (array_type) {
1058 case kExternalByteArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001059 __ ldrsb(value, MemOperand(r3, key, LSR, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001060 break;
1061 case kExternalUnsignedByteArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001062 __ ldrb(value, MemOperand(r3, key, LSR, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001063 break;
1064 case kExternalShortArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001065 __ ldrsh(value, MemOperand(r3, key, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001066 break;
1067 case kExternalUnsignedShortArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001068 __ ldrh(value, MemOperand(r3, key, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001069 break;
1070 case kExternalIntArray:
1071 case kExternalUnsignedIntArray:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001072 __ ldr(value, MemOperand(r3, key, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001073 break;
1074 case kExternalFloatArray:
1075 if (CpuFeatures::IsSupported(VFP3)) {
1076 CpuFeatures::Scope scope(VFP3);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001077 __ add(r2, r3, Operand(key, LSL, 1));
1078 __ vldr(s0, r2, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001079 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001080 __ ldr(value, MemOperand(r3, key, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001081 }
1082 break;
1083 default:
1084 UNREACHABLE();
1085 break;
1086 }
1087
1088 // For integer array types:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001089 // r2: value
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001090 // For floating-point array type
1091 // s0: value (if VFP3 is supported)
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001092 // r2: value (if VFP3 is not supported)
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001093
1094 if (array_type == kExternalIntArray) {
1095 // For the Int and UnsignedInt array types, we need to see whether
1096 // the value can be represented in a Smi. If not, we need to convert
1097 // it to a HeapNumber.
1098 Label box_int;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001099 __ cmp(value, Operand(0xC0000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001100 __ b(mi, &box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001101 // Tag integer as smi and return it.
1102 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001103 __ Ret();
1104
1105 __ bind(&box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001106 // Allocate a HeapNumber for the result and perform int-to-double
1107 // conversion. Use r0 for result as key is not needed any more.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001108 __ AllocateHeapNumber(r0, r3, r4, &slow);
1109
1110 if (CpuFeatures::IsSupported(VFP3)) {
1111 CpuFeatures::Scope scope(VFP3);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001112 __ vmov(s0, value);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001113 __ vcvt_f64_s32(d0, s0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001114 __ sub(r3, r0, Operand(kHeapObjectTag));
1115 __ vstr(d0, r3, HeapNumber::kValueOffset);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001116 __ Ret();
1117 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001118 WriteInt32ToHeapNumberStub stub(value, r0, r3);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001119 __ TailCallStub(&stub);
1120 }
1121 } else if (array_type == kExternalUnsignedIntArray) {
1122 // The test is different for unsigned int values. Since we need
1123 // the value to be in the range of a positive smi, we can't
1124 // handle either of the top two bits being set in the value.
1125 if (CpuFeatures::IsSupported(VFP3)) {
1126 CpuFeatures::Scope scope(VFP3);
1127 Label box_int, done;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001128 __ tst(value, Operand(0xC0000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001129 __ b(ne, &box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001130 // Tag integer as smi and return it.
1131 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001132 __ Ret();
1133
1134 __ bind(&box_int);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001135 __ vmov(s0, value);
1136 // Allocate a HeapNumber for the result and perform int-to-double
1137 // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all
1138 // registers - also when jumping due to exhausted young space.
1139 __ AllocateHeapNumber(r2, r3, r4, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001140
1141 __ vcvt_f64_u32(d0, s0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001142 __ sub(r1, r2, Operand(kHeapObjectTag));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001143 __ vstr(d0, r1, HeapNumber::kValueOffset);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001144
1145 __ mov(r0, r2);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001146 __ Ret();
1147 } else {
1148 // Check whether unsigned integer fits into smi.
1149 Label box_int_0, box_int_1, done;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001150 __ tst(value, Operand(0x80000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001151 __ b(ne, &box_int_0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001152 __ tst(value, Operand(0x40000000));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001153 __ b(ne, &box_int_1);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001154 // Tag integer as smi and return it.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001155 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001156 __ Ret();
1157
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001158 Register hiword = value; // r2.
1159 Register loword = r3;
1160
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001161 __ bind(&box_int_0);
1162 // Integer does not have leading zeros.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001163 GenerateUInt2Double(masm, hiword, loword, r4, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001164 __ b(&done);
1165
1166 __ bind(&box_int_1);
1167 // Integer has one leading zero.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001168 GenerateUInt2Double(masm, hiword, loword, r4, 1);
1169
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001170
1171 __ bind(&done);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001172 // Integer was converted to double in registers hiword:loword.
1173 // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber
1174 // clobbers all registers - also when jumping due to exhausted young
1175 // space.
1176 __ AllocateHeapNumber(r4, r5, r6, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001177
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001178 __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset));
1179 __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001180
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001181 __ mov(r0, r4);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001182 __ Ret();
1183 }
1184 } else if (array_type == kExternalFloatArray) {
1185 // For the floating-point array type, we need to always allocate a
1186 // HeapNumber.
1187 if (CpuFeatures::IsSupported(VFP3)) {
1188 CpuFeatures::Scope scope(VFP3);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001189 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
1190 // AllocateHeapNumber clobbers all registers - also when jumping due to
1191 // exhausted young space.
1192 __ AllocateHeapNumber(r2, r3, r4, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001193 __ vcvt_f64_f32(d0, s0);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001194 __ sub(r1, r2, Operand(kHeapObjectTag));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001195 __ vstr(d0, r1, HeapNumber::kValueOffset);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001196
1197 __ mov(r0, r2);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001198 __ Ret();
1199 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001200 // Allocate a HeapNumber for the result. Don't use r0 and r1 as
1201 // AllocateHeapNumber clobbers all registers - also when jumping due to
1202 // exhausted young space.
1203 __ AllocateHeapNumber(r3, r4, r5, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001204 // VFP is not available, do manual single to double conversion.
1205
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001206 // r2: floating point value (binary32)
1207 // r3: heap number for result
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001208
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001209 // Extract mantissa to r0. OK to clobber r0 now as there are no jumps to
1210 // the slow case from here.
1211 __ and_(r0, value, Operand(kBinary32MantissaMask));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001212
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001213 // Extract exponent to r1. OK to clobber r1 now as there are no jumps to
1214 // the slow case from here.
1215 __ mov(r1, Operand(value, LSR, kBinary32MantissaBits));
1216 __ and_(r1, r1, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001217
1218 Label exponent_rebiased;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001219 __ teq(r1, Operand(0x00));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001220 __ b(eq, &exponent_rebiased);
1221
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001222 __ teq(r1, Operand(0xff));
1223 __ mov(r1, Operand(0x7ff), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001224 __ b(eq, &exponent_rebiased);
1225
1226 // Rebias exponent.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001227 __ add(r1,
1228 r1,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001229 Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
1230
1231 __ bind(&exponent_rebiased);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001232 __ and_(r2, value, Operand(kBinary32SignMask));
1233 value = no_reg;
1234 __ orr(r2, r2, Operand(r1, LSL, HeapNumber::kMantissaBitsInTopWord));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001235
1236 // Shift mantissa.
1237 static const int kMantissaShiftForHiWord =
1238 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
1239
1240 static const int kMantissaShiftForLoWord =
1241 kBitsPerInt - kMantissaShiftForHiWord;
1242
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001243 __ orr(r2, r2, Operand(r0, LSR, kMantissaShiftForHiWord));
1244 __ mov(r0, Operand(r0, LSL, kMantissaShiftForLoWord));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001245
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001246 __ str(r2, FieldMemOperand(r3, HeapNumber::kExponentOffset));
1247 __ str(r0, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
1248
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001249 __ mov(r0, r3);
1250 __ Ret();
1251 }
1252
1253 } else {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001254 // Tag integer as smi and return it.
1255 __ mov(r0, Operand(value, LSL, kSmiTagSize));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001256 __ Ret();
1257 }
1258
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001259 // Slow case, key and receiver still in r0 and r1.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001260 __ bind(&slow);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001261 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1, r2, r3);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001262 GenerateRuntimeGetProperty(masm);
ager@chromium.org3811b432009-10-28 14:53:37 +00001263}
1264
1265
ager@chromium.org5c838252010-02-19 08:53:10 +00001266void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1267 // ---------- S t a t e --------------
1268 // -- lr : return address
ager@chromium.orgac091b72010-05-05 07:34:42 +00001269 // -- r0 : key
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001270 // -- r1 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001271 // -----------------------------------
1272 Label slow;
1273
ager@chromium.org5c838252010-02-19 08:53:10 +00001274 // Check that the receiver isn't a smi.
1275 __ BranchOnSmi(r1, &slow);
1276
1277 // Check that the key is a smi.
1278 __ BranchOnNotSmi(r0, &slow);
1279
1280 // Get the map of the receiver.
1281 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1282
1283 // Check that it has indexed interceptor and access checks
1284 // are not enabled for this object.
1285 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1286 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1287 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1288 __ b(ne, &slow);
1289
1290 // Everything is fine, call runtime.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001291 __ Push(r1, r0); // Receiver, key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001292
1293 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001294 __ TailCallExternalReference(ExternalReference(
ager@chromium.org5c838252010-02-19 08:53:10 +00001295 IC_Utility(kKeyedLoadPropertyWithInterceptor)), 2, 1);
1296
1297 __ bind(&slow);
1298 GenerateMiss(masm);
1299}
1300
1301
1302void KeyedStoreIC::GenerateMiss(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001303 // ---------- S t a t e --------------
1304 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001305 // -- r1 : key
1306 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001307 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001308 // -----------------------------------
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001309
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001310 // Push receiver, key and value for runtime call.
1311 __ Push(r2, r1, r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001312
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001313 ExternalReference ref = ExternalReference(IC_Utility(kKeyedStoreIC_Miss));
1314 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001315}
1316
1317
1318void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm) {
1319 // ---------- S t a t e --------------
1320 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001321 // -- r1 : key
1322 // -- r2 : receiver
ager@chromium.org5c838252010-02-19 08:53:10 +00001323 // -- lr : return address
ager@chromium.org5c838252010-02-19 08:53:10 +00001324 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001325
1326 // Push receiver, key and value for runtime call.
1327 __ Push(r2, r1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001328
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001329 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330}
1331
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001334 // ---------- S t a t e --------------
1335 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001336 // -- r1 : key
1337 // -- r2 : receiver
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001338 // -- lr : return address
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001339 // -----------------------------------
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001340 Label slow, fast, array, extra, check_pixel_array;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001341
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001342 // Register usage.
1343 Register value = r0;
1344 Register key = r1;
1345 Register receiver = r2;
1346 Register elements = r3; // Elements array of the receiver.
1347 // r4 and r5 are used as general scratch registers.
1348
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001349 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001350 __ tst(key, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001351 __ b(ne, &slow);
1352 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001353 __ tst(receiver, Operand(kSmiTagMask));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001354 __ b(eq, &slow);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001355 // Get the map of the object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001356 __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001357 // Check that the receiver does not require access checks. We need
1358 // to do this because this generic stub does not perform map checks.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001359 __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
ager@chromium.org8bb60582008-12-11 12:02:20 +00001360 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1361 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001362 // Check if the object is a JS array or not.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001363 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
1364 __ cmp(r4, Operand(JS_ARRAY_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001365 __ b(eq, &array);
1366 // Check that the object is some kind of JS object.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001367 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001368 __ b(lt, &slow);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001369
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001370 // Object case: Check key against length in the elements array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001371 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001372 // Check that the object is in fast mode (not dictionary).
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001373 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001374 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001375 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001376 __ b(ne, &check_pixel_array);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001377 // Check array bounds. Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001378 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001379 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001380 __ b(lo, &fast);
1381
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001382 // Slow case, handle jump to runtime.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001383 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001384 // Entry registers are intact.
1385 // r0: value.
1386 // r1: key.
1387 // r2: receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001388 GenerateRuntimeSetProperty(masm);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001389
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001390 // Check whether the elements is a pixel array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001391 // r4: elements map.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001392 __ bind(&check_pixel_array);
1393 __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001394 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001395 __ b(ne, &slow);
1396 // Check that the value is a smi. If a conversion is needed call into the
1397 // runtime to convert and clamp.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001398 __ BranchOnNotSmi(value, &slow);
1399 __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the key.
1400 __ ldr(ip, FieldMemOperand(elements, PixelArray::kLengthOffset));
1401 __ cmp(r4, Operand(ip));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001402 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001403 __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001404 { // Clamp the value to [0..255].
1405 Label done;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001406 __ tst(r5, Operand(0xFFFFFF00));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001407 __ b(eq, &done);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001408 __ mov(r5, Operand(0), LeaveCC, mi); // 0 if negative.
1409 __ mov(r5, Operand(255), LeaveCC, pl); // 255 if positive.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001410 __ bind(&done);
1411 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001412 // Get the pointer to the external array. This clobbers elements.
1413 __ ldr(elements,
1414 FieldMemOperand(elements, PixelArray::kExternalPointerOffset));
1415 __ strb(r5, MemOperand(elements, r4)); // Elements is now external array.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001416 __ Ret();
1417
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001418 // Extra capacity case: Check if there is extra capacity to
1419 // perform the store and update the length. Used for adding one
1420 // element to the array by writing to array[array.length].
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001421 __ bind(&extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001422 // Condition code from comparing key and array length is still available.
1423 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1424 // Check for room in the elements backing store.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001425 // Both the key and the length of FixedArray are smis.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001426 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001427 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001428 __ b(hs, &slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001429 // Calculate key + 1 as smi.
1430 ASSERT_EQ(0, kSmiTag);
1431 __ add(r4, key, Operand(Smi::FromInt(1)));
1432 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001433 __ b(&fast);
1434
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001435 // Array case: Get the length and the elements array from the JS
1436 // array. Check that the array is in fast mode; if it is the
1437 // length is always a smi.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001438 __ bind(&array);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001439 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1440 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001441 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001442 __ cmp(r4, ip);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001443 __ b(ne, &slow);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001444
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001445 // Check the key against the length in the array.
1446 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1447 __ cmp(key, Operand(ip));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001448 __ b(hs, &extra);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001449 // Fall through to fast case.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001450
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001451 __ bind(&fast);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001452 // Fast case, store the value to the elements backing store.
1453 __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1454 __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1455 __ str(value, MemOperand(r5));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001456 // Skip write barrier if the written value is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001457 __ tst(value, Operand(kSmiTagMask));
1458 __ Ret(eq);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001459 // Update write barrier for the elements array address.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001460 __ sub(r4, r5, Operand(elements));
1461 __ RecordWrite(elements, r4, r5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001462
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001463 __ Ret();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464}
1465
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001466
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001467// Convert int passed in register ival to IEE 754 single precision
1468// floating point value and store it into register fval.
1469// If VFP3 is available use it for conversion.
1470static void ConvertIntToFloat(MacroAssembler* masm,
1471 Register ival,
1472 Register fval,
1473 Register scratch1,
1474 Register scratch2) {
1475 if (CpuFeatures::IsSupported(VFP3)) {
1476 CpuFeatures::Scope scope(VFP3);
1477 __ vmov(s0, ival);
1478 __ vcvt_f32_s32(s0, s0);
1479 __ vmov(fval, s0);
1480 } else {
1481 Label not_special, done;
1482 // Move sign bit from source to destination. This works because the sign
1483 // bit in the exponent word of the double has the same position and polarity
1484 // as the 2's complement sign bit in a Smi.
1485 ASSERT(kBinary32SignMask == 0x80000000u);
1486
1487 __ and_(fval, ival, Operand(kBinary32SignMask), SetCC);
1488 // Negate value if it is negative.
1489 __ rsb(ival, ival, Operand(0), LeaveCC, ne);
1490
1491 // We have -1, 0 or 1, which we treat specially. Register ival contains
1492 // absolute value: it is either equal to 1 (special case of -1 and 1),
1493 // greater than 1 (not a special case) or less than 1 (special case of 0).
1494 __ cmp(ival, Operand(1));
1495 __ b(gt, &not_special);
1496
1497 // For 1 or -1 we need to or in the 0 exponent (biased).
1498 static const uint32_t exponent_word_for_1 =
1499 kBinary32ExponentBias << kBinary32ExponentShift;
1500
1501 __ orr(fval, fval, Operand(exponent_word_for_1), LeaveCC, eq);
1502 __ b(&done);
1503
1504 __ bind(&not_special);
1505 // Count leading zeros.
1506 // Gets the wrong answer for 0, but we already checked for that case above.
1507 Register zeros = scratch2;
1508 __ CountLeadingZeros(ival, scratch1, zeros);
1509
1510 // Compute exponent and or it into the exponent register.
1511 __ rsb(scratch1,
1512 zeros,
1513 Operand((kBitsPerInt - 1) + kBinary32ExponentBias));
1514
1515 __ orr(fval,
1516 fval,
1517 Operand(scratch1, LSL, kBinary32ExponentShift));
1518
1519 // Shift up the source chopping the top bit off.
1520 __ add(zeros, zeros, Operand(1));
1521 // This wouldn't work for 1 and -1 as the shift would be 32 which means 0.
1522 __ mov(ival, Operand(ival, LSL, zeros));
1523 // And the top (top 20 bits).
1524 __ orr(fval,
1525 fval,
1526 Operand(ival, LSR, kBitsPerInt - kBinary32MantissaBits));
1527
1528 __ bind(&done);
1529 }
1530}
1531
1532
1533static bool IsElementTypeSigned(ExternalArrayType array_type) {
1534 switch (array_type) {
1535 case kExternalByteArray:
1536 case kExternalShortArray:
1537 case kExternalIntArray:
1538 return true;
1539
1540 case kExternalUnsignedByteArray:
1541 case kExternalUnsignedShortArray:
1542 case kExternalUnsignedIntArray:
1543 return false;
1544
1545 default:
1546 UNREACHABLE();
1547 return false;
1548 }
1549}
1550
1551
ager@chromium.org3811b432009-10-28 14:53:37 +00001552void KeyedStoreIC::GenerateExternalArray(MacroAssembler* masm,
1553 ExternalArrayType array_type) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001554 // ---------- S t a t e --------------
1555 // -- r0 : value
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001556 // -- r1 : key
1557 // -- r2 : receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001558 // -- lr : return address
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001559 // -----------------------------------
1560 Label slow, check_heap_number;
1561
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001562 // Register usage.
1563 Register value = r0;
1564 Register key = r1;
1565 Register receiver = r2;
1566 // r3 mostly holds the elements array or the destination external array.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001567
1568 // Check that the object isn't a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001569 __ BranchOnSmi(receiver, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001570
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001571 // Check that the object is a JS object. Load map into r3.
1572 __ CompareObjectType(receiver, r3, r4, FIRST_JS_OBJECT_TYPE);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001573 __ b(le, &slow);
1574
1575 // Check that the receiver does not require access checks. We need
1576 // to do this because this generic stub does not perform map checks.
1577 __ ldrb(ip, FieldMemOperand(r3, Map::kBitFieldOffset));
1578 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1579 __ b(ne, &slow);
1580
1581 // Check that the key is a smi.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001582 __ BranchOnNotSmi(key, &slow);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001583
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001584 // Check that the elements array is the appropriate type of ExternalArray.
1585 __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
1586 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001587 __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001588 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001589 __ b(ne, &slow);
1590
1591 // Check that the index is in range.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001592 __ mov(r4, Operand(key, ASR, kSmiTagSize)); // Untag the index.
1593 __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
1594 __ cmp(r4, ip);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001595 // Unsigned comparison catches both negative and too-large values.
1596 __ b(hs, &slow);
1597
1598 // Handle both smis and HeapNumbers in the fast path. Go to the
1599 // runtime for all other kinds of values.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001600 // r3: external array.
1601 // r4: key (integer).
1602 __ BranchOnNotSmi(value, &check_heap_number);
1603 __ mov(r5, Operand(value, ASR, kSmiTagSize)); // Untag the value.
1604 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001605
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001606 // r3: base pointer of external storage.
1607 // r4: key (integer).
1608 // r5: value (integer).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001609 switch (array_type) {
1610 case kExternalByteArray:
1611 case kExternalUnsignedByteArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001612 __ strb(r5, MemOperand(r3, r4, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001613 break;
1614 case kExternalShortArray:
1615 case kExternalUnsignedShortArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001616 __ strh(r5, MemOperand(r3, r4, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001617 break;
1618 case kExternalIntArray:
1619 case kExternalUnsignedIntArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001620 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001621 break;
1622 case kExternalFloatArray:
1623 // Need to perform int-to-float conversion.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001624 ConvertIntToFloat(masm, r5, r6, r7, r9);
1625 __ str(r6, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001626 break;
1627 default:
1628 UNREACHABLE();
1629 break;
1630 }
1631
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001632 // Entry registers are intact, r0 holds the value which is the return value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001633 __ Ret();
1634
1635
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001636 // r3: external array.
1637 // r4: index (integer).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001638 __ bind(&check_heap_number);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001639 __ CompareObjectType(value, r5, r6, HEAP_NUMBER_TYPE);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001640 __ b(ne, &slow);
1641
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001642 __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
1643
1644 // r3: base pointer of external storage.
1645 // r4: key (integer).
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001646
1647 // The WebGL specification leaves the behavior of storing NaN and
1648 // +/-Infinity into integer arrays basically undefined. For more
1649 // reproducible behavior, convert these to zero.
1650 if (CpuFeatures::IsSupported(VFP3)) {
1651 CpuFeatures::Scope scope(VFP3);
1652
1653 // vldr requires offset to be a multiple of 4 so we can not
1654 // include -kHeapObjectTag into it.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001655 __ sub(r5, r0, Operand(kHeapObjectTag));
1656 __ vldr(d0, r5, HeapNumber::kValueOffset);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001657
1658 if (array_type == kExternalFloatArray) {
1659 __ vcvt_f32_f64(s0, d0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001660 __ vmov(r5, s0);
1661 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001662 } else {
1663 Label done;
1664
1665 // Need to perform float-to-int conversion.
1666 // Test for NaN.
1667 __ vcmp(d0, d0);
1668 // Move vector status bits to normal status bits.
1669 __ vmrs(v8::internal::pc);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001670 __ mov(r5, Operand(0), LeaveCC, vs); // NaN converts to 0.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001671 __ b(vs, &done);
1672
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001673 // Test whether exponent equal to 0x7FF (infinity or NaN).
1674 __ vmov(r6, r7, d0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001675 __ mov(r5, Operand(0x7FF00000));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001676 __ and_(r6, r6, Operand(r5));
1677 __ teq(r6, Operand(r5));
1678 __ mov(r6, Operand(0), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001679
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001680 // Not infinity or NaN simply convert to int.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001681 if (IsElementTypeSigned(array_type)) {
1682 __ vcvt_s32_f64(s0, d0, ne);
1683 } else {
1684 __ vcvt_u32_f64(s0, d0, ne);
1685 }
1686
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001687 __ vmov(r5, s0, ne);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001688
1689 __ bind(&done);
1690 switch (array_type) {
1691 case kExternalByteArray:
1692 case kExternalUnsignedByteArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001693 __ strb(r5, MemOperand(r3, r4, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001694 break;
1695 case kExternalShortArray:
1696 case kExternalUnsignedShortArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001697 __ strh(r5, MemOperand(r3, r4, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001698 break;
1699 case kExternalIntArray:
1700 case kExternalUnsignedIntArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001701 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001702 break;
1703 default:
1704 UNREACHABLE();
1705 break;
1706 }
1707 }
1708
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001709 // Entry registers are intact, r0 holds the value which is the return value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001710 __ Ret();
1711 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001712 // VFP3 is not available do manual conversions.
1713 __ ldr(r5, FieldMemOperand(value, HeapNumber::kExponentOffset));
1714 __ ldr(r6, FieldMemOperand(value, HeapNumber::kMantissaOffset));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001715
1716 if (array_type == kExternalFloatArray) {
1717 Label done, nan_or_infinity_or_zero;
1718 static const int kMantissaInHiWordShift =
1719 kBinary32MantissaBits - HeapNumber::kMantissaBitsInTopWord;
1720
1721 static const int kMantissaInLoWordShift =
1722 kBitsPerInt - kMantissaInHiWordShift;
1723
1724 // Test for all special exponent values: zeros, subnormal numbers, NaNs
1725 // and infinities. All these should be converted to 0.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001726 __ mov(r7, Operand(HeapNumber::kExponentMask));
1727 __ and_(r9, r5, Operand(r7), SetCC);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001728 __ b(eq, &nan_or_infinity_or_zero);
1729
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001730 __ teq(r9, Operand(r7));
1731 __ mov(r9, Operand(kBinary32ExponentMask), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001732 __ b(eq, &nan_or_infinity_or_zero);
1733
1734 // Rebias exponent.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001735 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
1736 __ add(r9,
1737 r9,
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001738 Operand(kBinary32ExponentBias - HeapNumber::kExponentBias));
1739
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001740 __ cmp(r9, Operand(kBinary32MaxExponent));
1741 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, gt);
1742 __ orr(r5, r5, Operand(kBinary32ExponentMask), LeaveCC, gt);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001743 __ b(gt, &done);
1744
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001745 __ cmp(r9, Operand(kBinary32MinExponent));
1746 __ and_(r5, r5, Operand(HeapNumber::kSignMask), LeaveCC, lt);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001747 __ b(lt, &done);
1748
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001749 __ and_(r7, r5, Operand(HeapNumber::kSignMask));
1750 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
1751 __ orr(r7, r7, Operand(r5, LSL, kMantissaInHiWordShift));
1752 __ orr(r7, r7, Operand(r6, LSR, kMantissaInLoWordShift));
1753 __ orr(r5, r7, Operand(r9, LSL, kBinary32ExponentShift));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001754
1755 __ bind(&done);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001756 __ str(r5, MemOperand(r3, r4, LSL, 2));
1757 // Entry registers are intact, r0 holds the value which is the return
1758 // value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001759 __ Ret();
1760
1761 __ bind(&nan_or_infinity_or_zero);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001762 __ and_(r7, r5, Operand(HeapNumber::kSignMask));
1763 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
1764 __ orr(r9, r9, r7);
1765 __ orr(r9, r9, Operand(r5, LSL, kMantissaInHiWordShift));
1766 __ orr(r5, r9, Operand(r6, LSR, kMantissaInLoWordShift));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001767 __ b(&done);
1768 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001769 bool is_signed_type = IsElementTypeSigned(array_type);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001770 int meaningfull_bits = is_signed_type ? (kBitsPerInt - 1) : kBitsPerInt;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001771 int32_t min_value = is_signed_type ? 0x80000000 : 0x00000000;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001772
1773 Label done, sign;
1774
1775 // Test for all special exponent values: zeros, subnormal numbers, NaNs
1776 // and infinities. All these should be converted to 0.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001777 __ mov(r7, Operand(HeapNumber::kExponentMask));
1778 __ and_(r9, r5, Operand(r7), SetCC);
1779 __ mov(r5, Operand(0), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001780 __ b(eq, &done);
1781
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001782 __ teq(r9, Operand(r7));
1783 __ mov(r5, Operand(0), LeaveCC, eq);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001784 __ b(eq, &done);
1785
1786 // Unbias exponent.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001787 __ mov(r9, Operand(r9, LSR, HeapNumber::kExponentShift));
1788 __ sub(r9, r9, Operand(HeapNumber::kExponentBias), SetCC);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001789 // If exponent is negative than result is 0.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001790 __ mov(r5, Operand(0), LeaveCC, mi);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001791 __ b(mi, &done);
1792
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001793 // If exponent is too big than result is minimal value.
1794 __ cmp(r9, Operand(meaningfull_bits - 1));
1795 __ mov(r5, Operand(min_value), LeaveCC, ge);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001796 __ b(ge, &done);
1797
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001798 __ and_(r7, r5, Operand(HeapNumber::kSignMask), SetCC);
1799 __ and_(r5, r5, Operand(HeapNumber::kMantissaMask));
1800 __ orr(r5, r5, Operand(1u << HeapNumber::kMantissaBitsInTopWord));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001801
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001802 __ rsb(r9, r9, Operand(HeapNumber::kMantissaBitsInTopWord), SetCC);
1803 __ mov(r5, Operand(r5, LSR, r9), LeaveCC, pl);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001804 __ b(pl, &sign);
1805
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001806 __ rsb(r9, r9, Operand(0));
1807 __ mov(r5, Operand(r5, LSL, r9));
1808 __ rsb(r9, r9, Operand(meaningfull_bits));
1809 __ orr(r5, r5, Operand(r6, LSR, r9));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001810
1811 __ bind(&sign);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001812 __ teq(r7, Operand(0));
1813 __ rsb(r5, r5, Operand(0), LeaveCC, ne);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001814
1815 __ bind(&done);
1816 switch (array_type) {
1817 case kExternalByteArray:
1818 case kExternalUnsignedByteArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001819 __ strb(r5, MemOperand(r3, r4, LSL, 0));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001820 break;
1821 case kExternalShortArray:
1822 case kExternalUnsignedShortArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001823 __ strh(r5, MemOperand(r3, r4, LSL, 1));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001824 break;
1825 case kExternalIntArray:
1826 case kExternalUnsignedIntArray:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001827 __ str(r5, MemOperand(r3, r4, LSL, 2));
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001828 break;
1829 default:
1830 UNREACHABLE();
1831 break;
1832 }
1833 }
1834 }
1835
1836 // Slow case: call runtime.
1837 __ bind(&slow);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001838
1839 // Entry registers are intact.
1840 // r0: value
1841 // r1: key
1842 // r2: receiver
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001843 GenerateRuntimeSetProperty(masm);
ager@chromium.org3811b432009-10-28 14:53:37 +00001844}
1845
1846
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001847void StoreIC::GenerateMegamorphic(MacroAssembler* masm) {
1848 // ----------- S t a t e -------------
1849 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001850 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851 // -- r2 : name
1852 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853 // -----------------------------------
1854
1855 // Get the receiver from the stack and probe the stub cache.
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001856 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1857 NOT_IN_LOOP,
1858 MONOMORPHIC);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001859 StubCache::GenerateProbe(masm, flags, r1, r2, r3, no_reg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860
1861 // Cache miss: Jump to runtime.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001862 GenerateMiss(masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863}
1864
1865
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001866void StoreIC::GenerateMiss(MacroAssembler* masm) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 // ----------- S t a t e -------------
1868 // -- r0 : value
ager@chromium.org5c838252010-02-19 08:53:10 +00001869 // -- r1 : receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 // -- r2 : name
1871 // -- lr : return address
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 // -----------------------------------
1873
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001874 __ Push(r1, r2, r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001875
mads.s.ager31e71382008-08-13 09:32:07 +00001876 // Perform tail call to the entry.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001877 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss));
1878 __ TailCallExternalReference(ref, 3, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001879}
1880
1881
ager@chromium.org5c838252010-02-19 08:53:10 +00001882void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1883 // ----------- S t a t e -------------
1884 // -- r0 : value
1885 // -- r1 : receiver
1886 // -- r2 : name
1887 // -- lr : return address
1888 // -----------------------------------
1889 //
1890 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1891 // (currently anything except for external and pixel arrays which means
1892 // anything with elements of FixedArray type.), but currently is restricted
1893 // to JSArray.
1894 // Value must be a number, but only smis are accepted as the most common case.
1895
1896 Label miss;
1897
1898 Register receiver = r1;
1899 Register value = r0;
1900 Register scratch = r3;
1901
1902 // Check that the receiver isn't a smi.
1903 __ BranchOnSmi(receiver, &miss);
1904
1905 // Check that the object is a JS array.
1906 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1907 __ b(ne, &miss);
1908
1909 // Check that elements are FixedArray.
1910 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1911 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1912 __ b(ne, &miss);
1913
1914 // Check that value is a smi.
1915 __ BranchOnNotSmi(value, &miss);
1916
1917 // Prepare tail call to StoreIC_ArrayLength.
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001918 __ Push(receiver, value);
ager@chromium.org5c838252010-02-19 08:53:10 +00001919
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001920 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength));
1921 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001922
1923 __ bind(&miss);
1924
1925 GenerateMiss(masm);
1926}
1927
1928
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929#undef __
1930
1931
1932} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001933
1934#endif // V8_TARGET_ARCH_ARM