blob: c88c25709247c40e5764fc2603c911ee6aa808ac [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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
Leon Clarkef7060e22010-06-03 12:02:55 +010030#if defined(V8_TARGET_ARCH_ARM)
31
Steve Block6ded16b2010-05-10 14:33:55 +010032#include "assembler-arm.h"
Kristian Monsen80d68ea2010-09-08 11:05:35 +010033#include "code-stubs.h"
Ben Murdoch8b112d22011-06-08 16:22:53 +010034#include "codegen.h"
Steve Block6ded16b2010-05-10 14:33:55 +010035#include "disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "ic-inl.h"
37#include "runtime.h"
38#include "stub-cache.h"
39
40namespace v8 {
41namespace internal {
42
43
44// ----------------------------------------------------------------------------
45// Static IC stub generators.
46//
47
48#define __ ACCESS_MASM(masm)
49
Steve Blocka7e24c12009-10-30 11:49:00 +000050
Steve Block8defd9f2010-07-08 12:39:36 +010051static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
52 Register type,
53 Label* global_object) {
54 // Register usage:
55 // type: holds the receiver instance type on entry.
56 __ cmp(type, Operand(JS_GLOBAL_OBJECT_TYPE));
57 __ b(eq, global_object);
58 __ cmp(type, Operand(JS_BUILTINS_OBJECT_TYPE));
59 __ b(eq, global_object);
60 __ cmp(type, Operand(JS_GLOBAL_PROXY_TYPE));
61 __ b(eq, global_object);
62}
Steve Blocka7e24c12009-10-30 11:49:00 +000063
Steve Block6ded16b2010-05-10 14:33:55 +010064
Steve Block8defd9f2010-07-08 12:39:36 +010065// Generated code falls through if the receiver is a regular non-global
66// JS object with slow properties and no interceptors.
67static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
68 Register receiver,
69 Register elements,
70 Register t0,
71 Register t1,
72 Label* miss) {
73 // Register usage:
74 // receiver: holds the receiver on entry and is unchanged.
75 // elements: holds the property dictionary on fall through.
76 // Scratch registers:
77 // t0: used to holds the receiver map.
78 // t1: used to holds the receiver instance type, receiver bit mask and
79 // elements map.
80
81 // Check that the receiver isn't a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000082 __ JumpIfSmi(receiver, miss);
Steve Block8defd9f2010-07-08 12:39:36 +010083
84 // Check that the receiver is a valid JS object.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000085 __ CompareObjectType(receiver, t0, t1, FIRST_SPEC_OBJECT_TYPE);
Steve Block8defd9f2010-07-08 12:39:36 +010086 __ b(lt, miss);
87
88 // If this assert fails, we have to check upper bound too.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000089 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
Steve Block8defd9f2010-07-08 12:39:36 +010090
91 GenerateGlobalInstanceTypeCheck(masm, t1, miss);
92
93 // Check that the global object does not require access checks.
94 __ ldrb(t1, FieldMemOperand(t0, Map::kBitFieldOffset));
95 __ tst(t1, Operand((1 << Map::kIsAccessCheckNeeded) |
96 (1 << Map::kHasNamedInterceptor)));
Steve Block1e0659c2011-05-24 12:43:12 +010097 __ b(ne, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +000098
Steve Block8defd9f2010-07-08 12:39:36 +010099 __ ldr(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
100 __ ldr(t1, FieldMemOperand(elements, HeapObject::kMapOffset));
101 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
102 __ cmp(t1, ip);
Steve Block1e0659c2011-05-24 12:43:12 +0100103 __ b(ne, miss);
Steve Block8defd9f2010-07-08 12:39:36 +0100104}
Steve Blocka7e24c12009-10-30 11:49:00 +0000105
Steve Blocka7e24c12009-10-30 11:49:00 +0000106
Steve Block8defd9f2010-07-08 12:39:36 +0100107// Helper function used from LoadIC/CallIC GenerateNormal.
108//
109// elements: Property dictionary. It is not clobbered if a jump to the miss
110// label is done.
111// name: Property name. It is not clobbered if a jump to the miss label is
112// done
113// result: Register for the result. It is only updated if a jump to the miss
114// label is not done. Can be the same as elements or name clobbering
115// one of these in the case of not jumping to the miss label.
116// The two scratch registers need to be different from elements, name and
117// result.
118// The generated code assumes that the receiver has slow properties,
119// is not a global object and does not have interceptors.
120static void GenerateDictionaryLoad(MacroAssembler* masm,
121 Label* miss,
122 Register elements,
123 Register name,
124 Register result,
125 Register scratch1,
126 Register scratch2) {
127 // Main use of the scratch registers.
128 // scratch1: Used as temporary and to hold the capacity of the property
129 // dictionary.
130 // scratch2: Used as temporary.
131 Label done;
132
133 // Probe the dictionary.
Ben Murdoch257744e2011-11-30 15:57:28 +0000134 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
135 miss,
136 &done,
137 elements,
138 name,
139 scratch1,
140 scratch2);
Steve Block8defd9f2010-07-08 12:39:36 +0100141
142 // If probing finds an entry check that the value is a normal
143 // property.
144 __ bind(&done); // scratch2 == elements + 4 * index
145 const int kElementsStartOffset = StringDictionary::kHeaderSize +
146 StringDictionary::kElementsStartIndex * kPointerSize;
147 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
148 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
Ben Murdoch589d6972011-11-30 16:04:58 +0000149 __ tst(scratch1, Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 __ b(ne, miss);
151
152 // Get the value at the masked, scaled index and return.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100153 __ ldr(result,
Steve Block8defd9f2010-07-08 12:39:36 +0100154 FieldMemOperand(scratch2, kElementsStartOffset + 1 * kPointerSize));
155}
156
157
158// Helper function used from StoreIC::GenerateNormal.
159//
160// elements: Property dictionary. It is not clobbered if a jump to the miss
161// label is done.
162// name: Property name. It is not clobbered if a jump to the miss label is
163// done
164// value: The value to store.
165// The two scratch registers need to be different from elements, name and
166// result.
167// The generated code assumes that the receiver has slow properties,
168// is not a global object and does not have interceptors.
169static void GenerateDictionaryStore(MacroAssembler* masm,
170 Label* miss,
171 Register elements,
172 Register name,
173 Register value,
174 Register scratch1,
175 Register scratch2) {
176 // Main use of the scratch registers.
177 // scratch1: Used as temporary and to hold the capacity of the property
178 // dictionary.
179 // scratch2: Used as temporary.
180 Label done;
181
182 // Probe the dictionary.
Ben Murdoch257744e2011-11-30 15:57:28 +0000183 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
184 miss,
185 &done,
186 elements,
187 name,
188 scratch1,
189 scratch2);
Steve Block8defd9f2010-07-08 12:39:36 +0100190
191 // If probing finds an entry in the dictionary check that the value
192 // is a normal property that is not read only.
193 __ bind(&done); // scratch2 == elements + 4 * index
194 const int kElementsStartOffset = StringDictionary::kHeaderSize +
195 StringDictionary::kElementsStartIndex * kPointerSize;
196 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
Ben Murdoch589d6972011-11-30 16:04:58 +0000197 const int kTypeAndReadOnlyMask =
198 (PropertyDetails::TypeField::kMask |
199 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
Steve Block8defd9f2010-07-08 12:39:36 +0100200 __ ldr(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
201 __ tst(scratch1, Operand(kTypeAndReadOnlyMask));
202 __ b(ne, miss);
203
204 // Store the value at the masked, scaled index and return.
205 const int kValueOffset = kElementsStartOffset + kPointerSize;
206 __ add(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
207 __ str(value, MemOperand(scratch2));
208
209 // Update the write barrier. Make sure not to clobber the value.
210 __ mov(scratch1, value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100211 __ RecordWrite(
212 elements, scratch2, scratch1, kLRHasNotBeenSaved, kDontSaveFPRegs);
Steve Block6ded16b2010-05-10 14:33:55 +0100213}
214
215
Steve Blocka7e24c12009-10-30 11:49:00 +0000216void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
217 // ----------- S t a t e -------------
218 // -- r2 : name
219 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100220 // -- r0 : receiver
221 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000223 Label miss;
224
Steve Blocka7e24c12009-10-30 11:49:00 +0000225 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
226 __ bind(&miss);
227 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
228}
229
230
Steve Block1e0659c2011-05-24 12:43:12 +0100231void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 // ----------- S t a t e -------------
233 // -- r2 : name
234 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100235 // -- r0 : receiver
236 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000237 // -----------------------------------
238 Label miss;
239
Steve Block1e0659c2011-05-24 12:43:12 +0100240 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
241 support_wrappers);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 // Cache miss: Jump to runtime.
243 __ bind(&miss);
244 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
245}
246
247
248void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
249 // ----------- S t a t e -------------
250 // -- r2 : name
251 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100252 // -- r0 : receiver
253 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000254 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000255 Label miss;
256
Steve Blocka7e24c12009-10-30 11:49:00 +0000257 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
258 __ bind(&miss);
259 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
260}
261
262
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100263// Checks the receiver for special cases (value type, slow case bits).
264// Falls through for regular JS object.
265static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
266 Register receiver,
Iain Merrick75681382010-08-19 15:07:18 +0100267 Register map,
268 Register scratch,
Steve Block8defd9f2010-07-08 12:39:36 +0100269 int interceptor_bit,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100270 Label* slow) {
271 // Check that the object isn't a smi.
Steve Block1e0659c2011-05-24 12:43:12 +0100272 __ JumpIfSmi(receiver, slow);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100273 // Get the map of the receiver.
Iain Merrick75681382010-08-19 15:07:18 +0100274 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100275 // Check bit field.
Iain Merrick75681382010-08-19 15:07:18 +0100276 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
277 __ tst(scratch,
Steve Block8defd9f2010-07-08 12:39:36 +0100278 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
Steve Block1e0659c2011-05-24 12:43:12 +0100279 __ b(ne, slow);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100280 // Check that the object is some kind of JS object EXCEPT JS Value type.
281 // In the case that the object is a value-wrapper object,
282 // we enter the runtime system to make sure that indexing into string
283 // objects work as intended.
284 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
Iain Merrick75681382010-08-19 15:07:18 +0100285 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
286 __ cmp(scratch, Operand(JS_OBJECT_TYPE));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100287 __ b(lt, slow);
288}
289
290
291// Loads an indexed element from a fast case array.
Iain Merrick75681382010-08-19 15:07:18 +0100292// If not_fast_array is NULL, doesn't perform the elements map check.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100293static void GenerateFastArrayLoad(MacroAssembler* masm,
294 Register receiver,
295 Register key,
296 Register elements,
297 Register scratch1,
298 Register scratch2,
299 Register result,
300 Label* not_fast_array,
301 Label* out_of_range) {
302 // Register use:
303 //
304 // receiver - holds the receiver on entry.
305 // Unchanged unless 'result' is the same register.
306 //
307 // key - holds the smi key on entry.
308 // Unchanged unless 'result' is the same register.
309 //
310 // elements - holds the elements of the receiver on exit.
311 //
312 // result - holds the result on exit if the load succeeded.
313 // Allowed to be the the same as 'receiver' or 'key'.
314 // Unchanged on bailout so 'receiver' and 'key' can be safely
315 // used by further computation.
316 //
317 // Scratch registers:
318 //
319 // scratch1 - used to hold elements map and elements length.
320 // Holds the elements map if not_fast_array branch is taken.
321 //
322 // scratch2 - used to hold the loaded value.
323
324 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
Iain Merrick75681382010-08-19 15:07:18 +0100325 if (not_fast_array != NULL) {
326 // Check that the object is in fast mode and writable.
327 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
328 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
329 __ cmp(scratch1, ip);
330 __ b(ne, not_fast_array);
331 } else {
332 __ AssertFastElements(elements);
333 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100334 // Check that the key (index) is within bounds.
335 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
336 __ cmp(key, Operand(scratch1));
337 __ b(hs, out_of_range);
338 // Fast case: Do the load.
339 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
340 // The key is a smi.
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000341 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100342 __ ldr(scratch2,
343 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
344 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
345 __ cmp(scratch2, ip);
346 // In case the loaded value is the_hole we have to consult GetProperty
347 // to ensure the prototype chain is searched.
348 __ b(eq, out_of_range);
349 __ mov(result, scratch2);
350}
351
352
353// Checks whether a key is an array index string or a symbol string.
354// Falls through if a key is a symbol.
355static void GenerateKeyStringCheck(MacroAssembler* masm,
356 Register key,
357 Register map,
358 Register hash,
359 Label* index_string,
360 Label* not_symbol) {
361 // The key is not a smi.
362 // Is it a string?
363 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
364 __ b(ge, not_symbol);
365
366 // Is the string an array index, with cached numeric value?
367 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
368 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
369 __ b(eq, index_string);
370
371 // Is the string a symbol?
372 // map: key map
373 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000374 STATIC_ASSERT(kSymbolTag != 0);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100375 __ tst(hash, Operand(kIsSymbolMask));
376 __ b(eq, not_symbol);
377}
378
379
Steve Blocka7e24c12009-10-30 11:49:00 +0000380// Defined in ic.cc.
381Object* CallIC_Miss(Arguments args);
382
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100383// The generated code does not accept smi keys.
384// The generated code falls through if both probes miss.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100385void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
386 int argc,
387 Code::Kind kind,
388 Code::ExtraICState extra_state) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 // ----------- S t a t e -------------
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100390 // -- r1 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +0000391 // -- r2 : name
Steve Blocka7e24c12009-10-30 11:49:00 +0000392 // -----------------------------------
393 Label number, non_number, non_string, boolean, probe, miss;
394
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 // Probe the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100396 Code::Flags flags = Code::ComputeFlags(kind,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100397 MONOMORPHIC,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100398 extra_state,
Ben Murdochb8e0da22011-05-16 14:20:40 +0100399 NORMAL,
400 argc);
Steve Block44f0eee2011-05-26 01:26:41 +0100401 Isolate::Current()->stub_cache()->GenerateProbe(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100402 masm, flags, r1, r2, r3, r4, r5, r6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000403
404 // If the stub cache probing failed, the receiver might be a value.
405 // For value objects, we use the map of the prototype objects for
406 // the corresponding JSValue for the cache and that is what we need
407 // to probe.
408 //
409 // Check for number.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000410 __ JumpIfSmi(r1, &number);
Steve Blocka7e24c12009-10-30 11:49:00 +0000411 __ CompareObjectType(r1, r3, r3, HEAP_NUMBER_TYPE);
412 __ b(ne, &non_number);
413 __ bind(&number);
414 StubCompiler::GenerateLoadGlobalFunctionPrototype(
415 masm, Context::NUMBER_FUNCTION_INDEX, r1);
416 __ b(&probe);
417
418 // Check for string.
419 __ bind(&non_number);
420 __ cmp(r3, Operand(FIRST_NONSTRING_TYPE));
421 __ b(hs, &non_string);
422 StubCompiler::GenerateLoadGlobalFunctionPrototype(
423 masm, Context::STRING_FUNCTION_INDEX, r1);
424 __ b(&probe);
425
426 // Check for boolean.
427 __ bind(&non_string);
428 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
429 __ cmp(r1, ip);
430 __ b(eq, &boolean);
431 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
432 __ cmp(r1, ip);
433 __ b(ne, &miss);
434 __ bind(&boolean);
435 StubCompiler::GenerateLoadGlobalFunctionPrototype(
436 masm, Context::BOOLEAN_FUNCTION_INDEX, r1);
437
438 // Probe the stub cache for the value object.
439 __ bind(&probe);
Steve Block44f0eee2011-05-26 01:26:41 +0100440 Isolate::Current()->stub_cache()->GenerateProbe(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100441 masm, flags, r1, r2, r3, r4, r5, r6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000442
Steve Blocka7e24c12009-10-30 11:49:00 +0000443 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000444}
445
446
Steve Block8defd9f2010-07-08 12:39:36 +0100447static void GenerateFunctionTailCall(MacroAssembler* masm,
448 int argc,
449 Label* miss,
450 Register scratch) {
451 // r1: function
Steve Blocka7e24c12009-10-30 11:49:00 +0000452
453 // Check that the value isn't a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000454 __ JumpIfSmi(r1, miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000455
456 // Check that the value is a JSFunction.
Steve Block6ded16b2010-05-10 14:33:55 +0100457 __ CompareObjectType(r1, scratch, scratch, JS_FUNCTION_TYPE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 __ b(ne, miss);
459
Steve Blocka7e24c12009-10-30 11:49:00 +0000460 // Invoke the function.
461 ParameterCount actual(argc);
Ben Murdoch257744e2011-11-30 15:57:28 +0000462 __ InvokeFunction(r1, actual, JUMP_FUNCTION,
463 NullCallWrapper(), CALL_AS_METHOD);
Steve Blocka7e24c12009-10-30 11:49:00 +0000464}
465
466
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100467void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000469 // -- r2 : name
470 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000471 // -----------------------------------
Steve Block8defd9f2010-07-08 12:39:36 +0100472 Label miss;
Steve Blocka7e24c12009-10-30 11:49:00 +0000473
474 // Get the receiver of the function from the stack into r1.
475 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000476
Steve Block8defd9f2010-07-08 12:39:36 +0100477 GenerateStringDictionaryReceiverCheck(masm, r1, r0, r3, r4, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478
Steve Block8defd9f2010-07-08 12:39:36 +0100479 // r0: elements
480 // Search the dictionary - put result in register r1.
481 GenerateDictionaryLoad(masm, &miss, r0, r2, r1, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000482
Steve Block8defd9f2010-07-08 12:39:36 +0100483 GenerateFunctionTailCall(masm, argc, &miss, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000484
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 __ bind(&miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000486}
487
488
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100489void CallICBase::GenerateMiss(MacroAssembler* masm,
490 int argc,
491 IC::UtilityId id,
492 Code::ExtraICState extra_state) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000493 // ----------- S t a t e -------------
Andrei Popescu402d9372010-02-26 13:31:12 +0000494 // -- r2 : name
495 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +0000496 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100497 Isolate* isolate = masm->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000498
Steve Block8defd9f2010-07-08 12:39:36 +0100499 if (id == IC::kCallIC_Miss) {
Steve Block44f0eee2011-05-26 01:26:41 +0100500 __ IncrementCounter(isolate->counters()->call_miss(), 1, r3, r4);
Steve Block8defd9f2010-07-08 12:39:36 +0100501 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100502 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, r3, r4);
Steve Block8defd9f2010-07-08 12:39:36 +0100503 }
504
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 // Get the receiver of the function from the stack.
Andrei Popescu402d9372010-02-26 13:31:12 +0000506 __ ldr(r3, MemOperand(sp, argc * kPointerSize));
Steve Blocka7e24c12009-10-30 11:49:00 +0000507
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100508 {
509 FrameScope scope(masm, StackFrame::INTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000510
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100511 // Push the receiver and the name of the function.
512 __ Push(r3, r2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000513
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100514 // Call the entry.
515 __ mov(r0, Operand(2));
516 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000517
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100518 CEntryStub stub(1);
519 __ CallStub(&stub);
Steve Blocka7e24c12009-10-30 11:49:00 +0000520
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100521 // Move result to r1 and leave the internal frame.
522 __ mov(r1, Operand(r0));
523 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000524
525 // Check if the receiver is a global object of some sort.
Steve Block8defd9f2010-07-08 12:39:36 +0100526 // This can happen only for regular CallIC but not KeyedCallIC.
527 if (id == IC::kCallIC_Miss) {
528 Label invoke, global;
529 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000530 __ JumpIfSmi(r2, &invoke);
Steve Block8defd9f2010-07-08 12:39:36 +0100531 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
532 __ b(eq, &global);
533 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
534 __ b(ne, &invoke);
Steve Blocka7e24c12009-10-30 11:49:00 +0000535
Steve Block8defd9f2010-07-08 12:39:36 +0100536 // Patch the receiver on the stack.
537 __ bind(&global);
538 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
539 __ str(r2, MemOperand(sp, argc * kPointerSize));
540 __ bind(&invoke);
541 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000542
543 // Invoke the function.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100544 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
Ben Murdoch257744e2011-11-30 15:57:28 +0000545 ? CALL_AS_FUNCTION
546 : CALL_AS_METHOD;
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 ParameterCount actual(argc);
Ben Murdoch257744e2011-11-30 15:57:28 +0000548 __ InvokeFunction(r1,
549 actual,
550 JUMP_FUNCTION,
551 NullCallWrapper(),
552 call_kind);
Steve Blocka7e24c12009-10-30 11:49:00 +0000553}
554
555
Ben Murdoch257744e2011-11-30 15:57:28 +0000556void CallIC::GenerateMegamorphic(MacroAssembler* masm,
557 int argc,
558 Code::ExtraICState extra_ic_state) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100559 // ----------- S t a t e -------------
560 // -- r2 : name
561 // -- lr : return address
562 // -----------------------------------
563
564 // Get the receiver of the function from the stack into r1.
565 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Ben Murdoch257744e2011-11-30 15:57:28 +0000566 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
567 GenerateMiss(masm, argc, extra_ic_state);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100568}
569
570
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100571void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100572 // ----------- S t a t e -------------
573 // -- r2 : name
574 // -- lr : return address
575 // -----------------------------------
576
577 // Get the receiver of the function from the stack into r1.
578 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
579
580 Label do_call, slow_call, slow_load, slow_reload_receiver;
581 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
582 Label index_smi, index_string;
583
584 // Check that the key is a smi.
Steve Block1e0659c2011-05-24 12:43:12 +0100585 __ JumpIfNotSmi(r2, &check_string);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100586 __ bind(&index_smi);
587 // Now the key is known to be a smi. This place is also jumped to from below
588 // where a numeric string is converted to a smi.
589
Steve Block8defd9f2010-07-08 12:39:36 +0100590 GenerateKeyedLoadReceiverCheck(
591 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100592
593 GenerateFastArrayLoad(
594 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
Steve Block44f0eee2011-05-26 01:26:41 +0100595 Counters* counters = masm->isolate()->counters();
596 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100597
598 __ bind(&do_call);
599 // receiver in r1 is not used after this point.
600 // r2: key
601 // r1: function
Steve Block8defd9f2010-07-08 12:39:36 +0100602 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100603
604 __ bind(&check_number_dictionary);
605 // r2: key
606 // r3: elements map
607 // r4: elements
608 // Check whether the elements is a number dictionary.
609 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
610 __ cmp(r3, ip);
611 __ b(ne, &slow_load);
612 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
613 // r0: untagged index
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000614 __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5);
Steve Block44f0eee2011-05-26 01:26:41 +0100615 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100616 __ jmp(&do_call);
617
618 __ bind(&slow_load);
619 // This branch is taken when calling KeyedCallIC_Miss is neither required
620 // nor beneficial.
Steve Block44f0eee2011-05-26 01:26:41 +0100621 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100622 {
623 FrameScope scope(masm, StackFrame::INTERNAL);
624 __ push(r2); // save the key
625 __ Push(r1, r2); // pass the receiver and the key
626 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
627 __ pop(r2); // restore the key
628 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100629 __ mov(r1, r0);
630 __ jmp(&do_call);
631
632 __ bind(&check_string);
633 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
634
635 // The key is known to be a symbol.
636 // If the receiver is a regular JS object with slow properties then do
637 // a quick inline probe of the receiver's dictionary.
638 // Otherwise do the monomorphic cache probe.
Steve Block8defd9f2010-07-08 12:39:36 +0100639 GenerateKeyedLoadReceiverCheck(
640 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100641
Steve Block8defd9f2010-07-08 12:39:36 +0100642 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
643 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100644 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
645 __ cmp(r3, ip);
646 __ b(ne, &lookup_monomorphic_cache);
647
Steve Block8defd9f2010-07-08 12:39:36 +0100648 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
Steve Block44f0eee2011-05-26 01:26:41 +0100649 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100650 __ jmp(&do_call);
651
652 __ bind(&lookup_monomorphic_cache);
Steve Block44f0eee2011-05-26 01:26:41 +0100653 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
Ben Murdoch257744e2011-11-30 15:57:28 +0000654 GenerateMonomorphicCacheProbe(masm,
655 argc,
656 Code::KEYED_CALL_IC,
657 Code::kNoExtraICState);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100658 // Fall through on miss.
659
660 __ bind(&slow_call);
661 // This branch is taken if:
662 // - the receiver requires boxing or access check,
663 // - the key is neither smi nor symbol,
664 // - the value loaded is not a function,
665 // - there is hope that the runtime will create a monomorphic call stub
666 // that will get fetched next time.
Steve Block44f0eee2011-05-26 01:26:41 +0100667 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100668 GenerateMiss(masm, argc);
669
670 __ bind(&index_string);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100671 __ IndexFromHash(r3, r2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100672 // Now jump to the place where smi keys are handled.
673 __ jmp(&index_smi);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100674}
675
676
677void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100678 // ----------- S t a t e -------------
679 // -- r2 : name
680 // -- lr : return address
681 // -----------------------------------
682
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100683 // Check if the name is a string.
684 Label miss;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000685 __ JumpIfSmi(r2, &miss);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100686 __ IsObjectJSStringType(r2, r0, &miss);
687
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100688 CallICBase::GenerateNormal(masm, argc);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100689 __ bind(&miss);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100690 GenerateMiss(masm, argc);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100691}
692
693
Steve Blocka7e24c12009-10-30 11:49:00 +0000694// Defined in ic.cc.
695Object* LoadIC_Miss(Arguments args);
696
697void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
698 // ----------- S t a t e -------------
699 // -- r2 : name
700 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100701 // -- r0 : receiver
702 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000703 // -----------------------------------
704
Steve Blocka7e24c12009-10-30 11:49:00 +0000705 // Probe the stub cache.
Ben Murdoch589d6972011-11-30 16:04:58 +0000706 Code::Flags flags =
707 Code::ComputeFlags(Code::LOAD_IC, MONOMORPHIC);
Steve Block44f0eee2011-05-26 01:26:41 +0100708 Isolate::Current()->stub_cache()->GenerateProbe(
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100709 masm, flags, r0, r2, r3, r4, r5, r6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000710
711 // Cache miss: Jump to runtime.
Andrei Popescu402d9372010-02-26 13:31:12 +0000712 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000713}
714
715
716void LoadIC::GenerateNormal(MacroAssembler* masm) {
717 // ----------- S t a t e -------------
718 // -- r2 : name
719 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100720 // -- r0 : receiver
721 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000722 // -----------------------------------
Steve Block8defd9f2010-07-08 12:39:36 +0100723 Label miss;
Steve Blocka7e24c12009-10-30 11:49:00 +0000724
Steve Block8defd9f2010-07-08 12:39:36 +0100725 GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000726
Steve Block8defd9f2010-07-08 12:39:36 +0100727 // r1: elements
728 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000729 __ Ret();
730
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100731 // Cache miss: Jump to runtime.
Steve Blocka7e24c12009-10-30 11:49:00 +0000732 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000733 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000734}
735
736
737void LoadIC::GenerateMiss(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000738 // ----------- S t a t e -------------
739 // -- r2 : name
740 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100741 // -- r0 : receiver
742 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100744 Isolate* isolate = masm->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000745
Steve Block44f0eee2011-05-26 01:26:41 +0100746 __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
Steve Block8defd9f2010-07-08 12:39:36 +0100747
Steve Block6ded16b2010-05-10 14:33:55 +0100748 __ mov(r3, r0);
749 __ Push(r3, r2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000750
751 // Perform tail call to the entry.
Steve Block44f0eee2011-05-26 01:26:41 +0100752 ExternalReference ref =
753 ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100754 __ TailCallExternalReference(ref, 2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000755}
756
Steve Block053d10c2011-06-13 19:13:29 +0100757
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000758static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
759 Register object,
760 Register key,
761 Register scratch1,
762 Register scratch2,
763 Register scratch3,
764 Label* unmapped_case,
765 Label* slow_case) {
766 Heap* heap = masm->isolate()->heap();
767
768 // Check that the receiver is a JSObject. Because of the map check
769 // later, we do not need to check for interceptors or whether it
770 // requires access checks.
771 __ JumpIfSmi(object, slow_case);
772 // Check that the object is some kind of JSObject.
773 __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE);
774 __ b(lt, slow_case);
775
776 // Check that the key is a positive smi.
Ben Murdoch7a930e02012-05-16 11:36:38 +0100777 __ tst(key, Operand(0x80000001));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000778 __ b(ne, slow_case);
779
780 // Load the elements into scratch1 and check its map.
781 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
782 __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
783 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
784
785 // Check if element is in the range of mapped arguments. If not, jump
786 // to the unmapped lookup with the parameter map in scratch1.
787 __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
788 __ sub(scratch2, scratch2, Operand(Smi::FromInt(2)));
789 __ cmp(key, Operand(scratch2));
790 __ b(cs, unmapped_case);
791
792 // Load element index and check whether it is the hole.
793 const int kOffset =
794 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
795
796 __ mov(scratch3, Operand(kPointerSize >> 1));
797 __ mul(scratch3, key, scratch3);
798 __ add(scratch3, scratch3, Operand(kOffset));
799
800 __ ldr(scratch2, MemOperand(scratch1, scratch3));
801 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
802 __ cmp(scratch2, scratch3);
803 __ b(eq, unmapped_case);
804
805 // Load value from context and return it. We can reuse scratch1 because
806 // we do not jump to the unmapped lookup (which requires the parameter
807 // map in scratch1).
808 __ ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
809 __ mov(scratch3, Operand(kPointerSize >> 1));
810 __ mul(scratch3, scratch2, scratch3);
811 __ add(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
812 return MemOperand(scratch1, scratch3);
813}
814
815
816static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
817 Register key,
818 Register parameter_map,
819 Register scratch,
820 Label* slow_case) {
821 // Element is in arguments backing store, which is referenced by the
822 // second element of the parameter_map. The parameter_map register
823 // must be loaded with the parameter map of the arguments object and is
824 // overwritten.
825 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
826 Register backing_store = parameter_map;
827 __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
828 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
829 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
830 DONT_DO_SMI_CHECK);
831 __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
832 __ cmp(key, Operand(scratch));
833 __ b(cs, slow_case);
834 __ mov(scratch, Operand(kPointerSize >> 1));
835 __ mul(scratch, key, scratch);
836 __ add(scratch,
837 scratch,
838 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
839 return MemOperand(backing_store, scratch);
840}
841
842
843void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
844 // ---------- S t a t e --------------
845 // -- lr : return address
846 // -- r0 : key
847 // -- r1 : receiver
848 // -----------------------------------
849 Label slow, notin;
850 MemOperand mapped_location =
851 GenerateMappedArgumentsLookup(masm, r1, r0, r2, r3, r4, &notin, &slow);
852 __ ldr(r0, mapped_location);
853 __ Ret();
854 __ bind(&notin);
855 // The unmapped lookup expects that the parameter map is in r2.
856 MemOperand unmapped_location =
857 GenerateUnmappedArgumentsLookup(masm, r0, r2, r3, &slow);
858 __ ldr(r2, unmapped_location);
859 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
860 __ cmp(r2, r3);
861 __ b(eq, &slow);
862 __ mov(r0, r2);
863 __ Ret();
864 __ bind(&slow);
865 GenerateMiss(masm, false);
866}
867
868
869void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
870 // ---------- S t a t e --------------
871 // -- r0 : value
872 // -- r1 : key
873 // -- r2 : receiver
874 // -- lr : return address
875 // -----------------------------------
876 Label slow, notin;
877 MemOperand mapped_location =
878 GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, &notin, &slow);
879 __ str(r0, mapped_location);
880 __ add(r6, r3, r5);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100881 __ mov(r9, r0);
882 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000883 __ Ret();
884 __ bind(&notin);
885 // The unmapped lookup expects that the parameter map is in r3.
886 MemOperand unmapped_location =
887 GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
888 __ str(r0, unmapped_location);
889 __ add(r6, r3, r4);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100890 __ mov(r9, r0);
891 __ RecordWrite(r3, r6, r9, kLRHasNotBeenSaved, kDontSaveFPRegs);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000892 __ Ret();
893 __ bind(&slow);
894 GenerateMiss(masm, false);
895}
896
897
898void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
899 int argc) {
900 // ----------- S t a t e -------------
901 // -- r2 : name
902 // -- lr : return address
903 // -----------------------------------
904 Label slow, notin;
905 // Load receiver.
906 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
907 MemOperand mapped_location =
908 GenerateMappedArgumentsLookup(masm, r1, r2, r3, r4, r5, &notin, &slow);
909 __ ldr(r1, mapped_location);
910 GenerateFunctionTailCall(masm, argc, &slow, r3);
911 __ bind(&notin);
912 // The unmapped lookup expects that the parameter map is in r3.
913 MemOperand unmapped_location =
914 GenerateUnmappedArgumentsLookup(masm, r2, r3, r4, &slow);
915 __ ldr(r1, unmapped_location);
916 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
917 __ cmp(r1, r3);
918 __ b(eq, &slow);
919 GenerateFunctionTailCall(masm, argc, &slow, r3);
920 __ bind(&slow);
921 GenerateMiss(masm, argc);
922}
923
924
925Object* KeyedLoadIC_Miss(Arguments args);
926
927
Ben Murdoch257744e2011-11-30 15:57:28 +0000928void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 // ---------- S t a t e --------------
930 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100931 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +0100932 // -- r1 : receiver
Leon Clarke4515c472010-02-03 11:58:03 +0000933 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100934 Isolate* isolate = masm->isolate();
Leon Clarke4515c472010-02-03 11:58:03 +0000935
Steve Block44f0eee2011-05-26 01:26:41 +0100936 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
Steve Block8defd9f2010-07-08 12:39:36 +0100937
Steve Block6ded16b2010-05-10 14:33:55 +0100938 __ Push(r1, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000939
Ben Murdoch257744e2011-11-30 15:57:28 +0000940 // Perform tail call to the entry.
941 ExternalReference ref = force_generic
942 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
943 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
944
Steve Block6ded16b2010-05-10 14:33:55 +0100945 __ TailCallExternalReference(ref, 2, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000946}
947
948
949void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
950 // ---------- S t a t e --------------
951 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100952 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +0100953 // -- r1 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +0000954 // -----------------------------------
955
Steve Block6ded16b2010-05-10 14:33:55 +0100956 __ Push(r1, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000957
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100958 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000959}
960
961
962void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
963 // ---------- S t a t e --------------
964 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100965 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +0100966 // -- r1 : receiver
Leon Clarke4515c472010-02-03 11:58:03 +0000967 // -----------------------------------
Ben Murdochbb769b22010-08-11 14:56:33 +0100968 Label slow, check_string, index_smi, index_string, property_array_property;
Steve Block44f0eee2011-05-26 01:26:41 +0100969 Label probe_dictionary, check_number_dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +0000970
Kristian Monsen25f61362010-05-21 11:50:48 +0100971 Register key = r0;
972 Register receiver = r1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000973
Steve Block44f0eee2011-05-26 01:26:41 +0100974 Isolate* isolate = masm->isolate();
975
Andrei Popescu402d9372010-02-26 13:31:12 +0000976 // Check that the key is a smi.
Steve Block1e0659c2011-05-24 12:43:12 +0100977 __ JumpIfNotSmi(key, &check_string);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100978 __ bind(&index_smi);
979 // Now the key is known to be a smi. This place is also jumped to from below
980 // where a numeric string is converted to a smi.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100981
Steve Block8defd9f2010-07-08 12:39:36 +0100982 GenerateKeyedLoadReceiverCheck(
983 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
984
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000985 // Check the receiver's map to see if it has fast elements.
986 __ CheckFastElements(r2, r3, &check_number_dictionary);
Iain Merrick75681382010-08-19 15:07:18 +0100987
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100988 GenerateFastArrayLoad(
Iain Merrick75681382010-08-19 15:07:18 +0100989 masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
Steve Block44f0eee2011-05-26 01:26:41 +0100990 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +0000991 __ Ret();
Steve Block6ded16b2010-05-10 14:33:55 +0100992
Steve Block6ded16b2010-05-10 14:33:55 +0100993 __ bind(&check_number_dictionary);
Steve Block44f0eee2011-05-26 01:26:41 +0100994 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
995 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
996
Steve Block6ded16b2010-05-10 14:33:55 +0100997 // Check whether the elements is a number dictionary.
Kristian Monsen25f61362010-05-21 11:50:48 +0100998 // r0: key
Kristian Monsen25f61362010-05-21 11:50:48 +0100999 // r3: elements map
1000 // r4: elements
Steve Block6ded16b2010-05-10 14:33:55 +01001001 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1002 __ cmp(r3, ip);
1003 __ b(ne, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001004 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001005 __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5);
Steve Block6ded16b2010-05-10 14:33:55 +01001006 __ Ret();
1007
Kristian Monsen25f61362010-05-21 11:50:48 +01001008 // Slow case, key and receiver still in r0 and r1.
Steve Block6ded16b2010-05-10 14:33:55 +01001009 __ bind(&slow);
Steve Block44f0eee2011-05-26 01:26:41 +01001010 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
1011 1, r2, r3);
Steve Block6ded16b2010-05-10 14:33:55 +01001012 GenerateRuntimeGetProperty(masm);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001013
1014 __ bind(&check_string);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001015 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001016
Steve Block8defd9f2010-07-08 12:39:36 +01001017 GenerateKeyedLoadReceiverCheck(
1018 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1019
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001020 // If the receiver is a fast-case object, check the keyed lookup
1021 // cache. Otherwise probe the dictionary.
1022 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
Steve Block8defd9f2010-07-08 12:39:36 +01001023 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001024 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
Steve Block8defd9f2010-07-08 12:39:36 +01001025 __ cmp(r4, ip);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001026 __ b(eq, &probe_dictionary);
1027
1028 // Load the map of the receiver, compute the keyed lookup cache hash
1029 // based on 32 bits of the map pointer and the string hash.
1030 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1031 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1032 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1033 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001034 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
1035 __ And(r3, r3, Operand(mask));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001036
1037 // Load the key (consisting of map and symbol) from the cache and
1038 // check for match.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001039 Label load_in_object_property;
1040 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
1041 Label hit_on_nth_entry[kEntriesPerBucket];
Steve Block44f0eee2011-05-26 01:26:41 +01001042 ExternalReference cache_keys =
1043 ExternalReference::keyed_lookup_cache_keys(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001044
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001045 __ mov(r4, Operand(cache_keys));
1046 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001047
1048 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
1049 Label try_next_entry;
1050 // Load map and move r4 to next entry.
1051 __ ldr(r5, MemOperand(r4, kPointerSize * 2, PostIndex));
1052 __ cmp(r2, r5);
1053 __ b(ne, &try_next_entry);
1054 __ ldr(r5, MemOperand(r4, -kPointerSize)); // Load symbol
1055 __ cmp(r0, r5);
1056 __ b(eq, &hit_on_nth_entry[i]);
1057 __ bind(&try_next_entry);
1058 }
1059
1060 // Last entry: Load map and move r4 to symbol.
1061 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001062 __ cmp(r2, r5);
1063 __ b(ne, &slow);
1064 __ ldr(r5, MemOperand(r4));
1065 __ cmp(r0, r5);
1066 __ b(ne, &slow);
1067
Ben Murdochbb769b22010-08-11 14:56:33 +01001068 // Get field offset.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001069 // r0 : key
1070 // r1 : receiver
1071 // r2 : receiver's map
1072 // r3 : lookup cache index
Steve Block44f0eee2011-05-26 01:26:41 +01001073 ExternalReference cache_field_offsets =
1074 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001075
1076 // Hit on nth entry.
1077 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
1078 __ bind(&hit_on_nth_entry[i]);
1079 __ mov(r4, Operand(cache_field_offsets));
1080 if (i != 0) {
1081 __ add(r3, r3, Operand(i));
1082 }
1083 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1084 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
1085 __ sub(r5, r5, r6, SetCC);
1086 __ b(ge, &property_array_property);
1087 if (i != 0) {
1088 __ jmp(&load_in_object_property);
1089 }
1090 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001091
1092 // Load in-object property.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001093 __ bind(&load_in_object_property);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001094 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1095 __ add(r6, r6, r5); // Index from start of object.
1096 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1097 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
Steve Block44f0eee2011-05-26 01:26:41 +01001098 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1099 1, r2, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001100 __ Ret();
1101
Ben Murdochbb769b22010-08-11 14:56:33 +01001102 // Load property array property.
1103 __ bind(&property_array_property);
1104 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1105 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1106 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
Steve Block44f0eee2011-05-26 01:26:41 +01001107 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1108 1, r2, r3);
Ben Murdochbb769b22010-08-11 14:56:33 +01001109 __ Ret();
1110
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001111 // Do a quick inline probe of the receiver's dictionary, if it
1112 // exists.
1113 __ bind(&probe_dictionary);
Steve Block8defd9f2010-07-08 12:39:36 +01001114 // r1: receiver
1115 // r0: key
1116 // r3: elements
1117 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1118 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1119 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001120 // Load the property to r0.
Steve Block8defd9f2010-07-08 12:39:36 +01001121 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
Steve Block44f0eee2011-05-26 01:26:41 +01001122 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1123 1, r2, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001124 __ Ret();
1125
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001126 __ bind(&index_string);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001127 __ IndexFromHash(r3, key);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001128 // Now jump to the place where smi keys are handled.
1129 __ jmp(&index_smi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001130}
1131
1132
Leon Clarkee46be812010-01-19 14:06:41 +00001133void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1134 // ---------- S t a t e --------------
1135 // -- lr : return address
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001136 // -- r0 : key (index)
Kristian Monsen25f61362010-05-21 11:50:48 +01001137 // -- r1 : receiver
Leon Clarke4515c472010-02-03 11:58:03 +00001138 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001139 Label miss;
Leon Clarke4515c472010-02-03 11:58:03 +00001140
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001141 Register receiver = r1;
Steve Block6ded16b2010-05-10 14:33:55 +01001142 Register index = r0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001143 Register scratch = r3;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001144 Register result = r0;
Steve Block6ded16b2010-05-10 14:33:55 +01001145
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001146 StringCharAtGenerator char_at_generator(receiver,
1147 index,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001148 scratch,
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001149 result,
1150 &miss, // When not a string.
1151 &miss, // When not a number.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001152 &miss, // When index out of range.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001153 STRING_INDEX_IS_ARRAY_INDEX);
1154 char_at_generator.GenerateFast(masm);
1155 __ Ret();
Steve Block6ded16b2010-05-10 14:33:55 +01001156
Ben Murdochb0fe1622011-05-05 13:52:32 +01001157 StubRuntimeCallHelper call_helper;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001158 char_at_generator.GenerateSlow(masm, call_helper);
Steve Block6ded16b2010-05-10 14:33:55 +01001159
Steve Block6ded16b2010-05-10 14:33:55 +01001160 __ bind(&miss);
Ben Murdoch257744e2011-11-30 15:57:28 +00001161 GenerateMiss(masm, false);
Leon Clarkee46be812010-01-19 14:06:41 +00001162}
1163
1164
Andrei Popescu402d9372010-02-26 13:31:12 +00001165void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1166 // ---------- S t a t e --------------
1167 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001168 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001169 // -- r1 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +00001170 // -----------------------------------
1171 Label slow;
1172
Andrei Popescu402d9372010-02-26 13:31:12 +00001173 // Check that the receiver isn't a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001174 __ JumpIfSmi(r1, &slow);
Andrei Popescu402d9372010-02-26 13:31:12 +00001175
Ben Murdochf87a2032010-10-22 12:50:53 +01001176 // Check that the key is an array index, that is Uint32.
1177 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1178 __ b(ne, &slow);
Andrei Popescu402d9372010-02-26 13:31:12 +00001179
1180 // Get the map of the receiver.
1181 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1182
1183 // Check that it has indexed interceptor and access checks
1184 // are not enabled for this object.
1185 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1186 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1187 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1188 __ b(ne, &slow);
1189
1190 // Everything is fine, call runtime.
Steve Block6ded16b2010-05-10 14:33:55 +01001191 __ Push(r1, r0); // Receiver, key.
Andrei Popescu402d9372010-02-26 13:31:12 +00001192
1193 // Perform tail call to the entry.
Steve Block44f0eee2011-05-26 01:26:41 +01001194 __ TailCallExternalReference(
1195 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
1196 masm->isolate()),
1197 2,
1198 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001199
1200 __ bind(&slow);
Ben Murdoch257744e2011-11-30 15:57:28 +00001201 GenerateMiss(masm, false);
Andrei Popescu402d9372010-02-26 13:31:12 +00001202}
1203
1204
Ben Murdoch257744e2011-11-30 15:57:28 +00001205void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001206 // ---------- S t a t e --------------
1207 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001208 // -- r1 : key
1209 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001210 // -- lr : return address
Leon Clarke4515c472010-02-03 11:58:03 +00001211 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001212
Leon Clarkef7060e22010-06-03 12:02:55 +01001213 // Push receiver, key and value for runtime call.
1214 __ Push(r2, r1, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001215
Ben Murdoch257744e2011-11-30 15:57:28 +00001216 ExternalReference ref = force_generic
1217 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1218 masm->isolate())
1219 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1220 __ TailCallExternalReference(ref, 3, 1);
1221}
1222
1223
1224void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1225 // ---------- S t a t e --------------
1226 // -- r0 : value
1227 // -- r1 : key
1228 // -- r2 : receiver
1229 // -- lr : return address
1230 // -----------------------------------
1231
1232 // Push receiver, key and value for runtime call.
1233 __ Push(r2, r1, r0);
1234
1235 // The slow case calls into the runtime to complete the store without causing
1236 // an IC miss that would otherwise cause a transition to the generic stub.
Steve Block44f0eee2011-05-26 01:26:41 +01001237 ExternalReference ref =
Ben Murdoch257744e2011-11-30 15:57:28 +00001238 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
Steve Block6ded16b2010-05-10 14:33:55 +01001239 __ TailCallExternalReference(ref, 3, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001240}
1241
1242
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001243void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1244 // ---------- S t a t e --------------
1245 // -- r2 : receiver
1246 // -- r3 : target map
1247 // -- lr : return address
1248 // -----------------------------------
1249 // Must return the modified receiver in r0.
1250 if (!FLAG_trace_elements_transitions) {
1251 Label fail;
1252 ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &fail);
1253 __ mov(r0, r2);
1254 __ Ret();
1255 __ bind(&fail);
1256 }
1257
1258 __ push(r2);
1259 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1260}
1261
1262
1263void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1264 MacroAssembler* masm) {
1265 // ---------- S t a t e --------------
1266 // -- r2 : receiver
1267 // -- r3 : target map
1268 // -- lr : return address
1269 // -----------------------------------
1270 // Must return the modified receiver in r0.
1271 if (!FLAG_trace_elements_transitions) {
1272 Label fail;
1273 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &fail);
1274 __ mov(r0, r2);
1275 __ Ret();
1276 __ bind(&fail);
1277 }
1278
1279 __ push(r2);
1280 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1281}
1282
1283
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001284void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1285 StrictModeFlag strict_mode) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001286 // ---------- S t a t e --------------
1287 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001288 // -- r1 : key
1289 // -- r2 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +00001290 // -- lr : return address
Andrei Popescu402d9372010-02-26 13:31:12 +00001291 // -----------------------------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001292
1293 // Push receiver, key and value for runtime call.
1294 __ Push(r2, r1, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001295
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001296 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1297 __ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1298 __ Push(r1, r0);
1299
1300 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001301}
1302
1303
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001304void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1305 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001306 // ---------- S t a t e --------------
1307 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001308 // -- r1 : key
1309 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 // -- lr : return address
Leon Clarke4515c472010-02-03 11:58:03 +00001311 // -----------------------------------
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001312 Label slow, array, extra, check_if_double_array;
1313 Label fast_object_with_map_check, fast_object_without_map_check;
1314 Label fast_double_with_map_check, fast_double_without_map_check;
1315 Label transition_smi_elements, finish_object_store, non_double_value;
1316 Label transition_double_elements;
Leon Clarke4515c472010-02-03 11:58:03 +00001317
Leon Clarkef7060e22010-06-03 12:02:55 +01001318 // Register usage.
1319 Register value = r0;
1320 Register key = r1;
1321 Register receiver = r2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001322 Register receiver_map = r3;
1323 Register elements_map = r6;
1324 Register elements = r7; // Elements array of the receiver.
Leon Clarkef7060e22010-06-03 12:02:55 +01001325 // r4 and r5 are used as general scratch registers.
1326
Steve Blocka7e24c12009-10-30 11:49:00 +00001327 // Check that the key is a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001328 __ JumpIfNotSmi(key, &slow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001329 // Check that the object isn't a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001330 __ JumpIfSmi(receiver, &slow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 // Get the map of the object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001332 __ ldr(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001333 // Check that the receiver does not require access checks. We need
1334 // to do this because this generic stub does not perform map checks.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001335 __ ldrb(ip, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001336 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1337 __ b(ne, &slow);
1338 // Check if the object is a JS array or not.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001339 __ ldrb(r4, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
Leon Clarkef7060e22010-06-03 12:02:55 +01001340 __ cmp(r4, Operand(JS_ARRAY_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +00001341 __ b(eq, &array);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001342 // Check that the object is some kind of JSObject.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001343 __ cmp(r4, Operand(FIRST_JS_OBJECT_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +00001344 __ b(lt, &slow);
1345
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 // Object case: Check key against length in the elements array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001347 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001348 // Check array bounds. Both the key and the length of FixedArray are smis.
Leon Clarkef7060e22010-06-03 12:02:55 +01001349 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001350 __ cmp(key, Operand(ip));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001351 __ b(lo, &fast_object_with_map_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001352
Leon Clarkef7060e22010-06-03 12:02:55 +01001353 // Slow case, handle jump to runtime.
Steve Blocka7e24c12009-10-30 11:49:00 +00001354 __ bind(&slow);
Leon Clarkef7060e22010-06-03 12:02:55 +01001355 // Entry registers are intact.
1356 // r0: value.
1357 // r1: key.
1358 // r2: receiver.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001359 GenerateRuntimeSetProperty(masm, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001360
1361 // Extra capacity case: Check if there is extra capacity to
1362 // perform the store and update the length. Used for adding one
1363 // element to the array by writing to array[array.length].
Steve Blocka7e24c12009-10-30 11:49:00 +00001364 __ bind(&extra);
Leon Clarkef7060e22010-06-03 12:02:55 +01001365 // Condition code from comparing key and array length is still available.
1366 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1367 // Check for room in the elements backing store.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001368 // Both the key and the length of FixedArray are smis.
Leon Clarkef7060e22010-06-03 12:02:55 +01001369 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001370 __ cmp(key, Operand(ip));
Steve Blocka7e24c12009-10-30 11:49:00 +00001371 __ b(hs, &slow);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001372 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1373 __ cmp(elements_map,
1374 Operand(masm->isolate()->factory()->fixed_array_map()));
1375 __ b(ne, &check_if_double_array);
Leon Clarkef7060e22010-06-03 12:02:55 +01001376 // Calculate key + 1 as smi.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001377 STATIC_ASSERT(kSmiTag == 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01001378 __ add(r4, key, Operand(Smi::FromInt(1)));
1379 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001380 __ b(&fast_object_without_map_check);
1381
1382 __ bind(&check_if_double_array);
1383 __ cmp(elements_map,
1384 Operand(masm->isolate()->factory()->fixed_double_array_map()));
1385 __ b(ne, &slow);
1386 // Add 1 to key, and go to common element store code for doubles.
1387 STATIC_ASSERT(kSmiTag == 0);
1388 __ add(r4, key, Operand(Smi::FromInt(1)));
1389 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
1390 __ jmp(&fast_double_without_map_check);
Steve Blocka7e24c12009-10-30 11:49:00 +00001391
Steve Blocka7e24c12009-10-30 11:49:00 +00001392 // Array case: Get the length and the elements array from the JS
Iain Merrick75681382010-08-19 15:07:18 +01001393 // array. Check that the array is in fast mode (and writable); if it
1394 // is the length is always a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001395 __ bind(&array);
Leon Clarkef7060e22010-06-03 12:02:55 +01001396 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001397
Leon Clarkef7060e22010-06-03 12:02:55 +01001398 // Check the key against the length in the array.
1399 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1400 __ cmp(key, Operand(ip));
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 __ b(hs, &extra);
Leon Clarkef7060e22010-06-03 12:02:55 +01001402 // Fall through to fast case.
Steve Blocka7e24c12009-10-30 11:49:00 +00001403
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001404 __ bind(&fast_object_with_map_check);
1405 Register scratch_value = r4;
1406 Register address = r5;
1407 __ ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1408 __ cmp(elements_map,
1409 Operand(masm->isolate()->factory()->fixed_array_map()));
1410 __ b(ne, &fast_double_with_map_check);
1411 __ bind(&fast_object_without_map_check);
1412 // Smi stores don't require further checks.
1413 Label non_smi_value;
1414 __ JumpIfNotSmi(value, &non_smi_value);
1415 // It's irrelevant whether array is smi-only or not when writing a smi.
1416 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1417 __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1418 __ str(value, MemOperand(address));
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001419 __ Ret();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001420
1421 __ bind(&non_smi_value);
1422 // Escape to elements kind transition case.
1423 __ CheckFastObjectElements(receiver_map, scratch_value,
1424 &transition_smi_elements);
1425 // Fast elements array, store the value to the elements backing store.
1426 __ bind(&finish_object_store);
1427 __ add(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1428 __ add(address, address, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1429 __ str(value, MemOperand(address));
1430 // Update write barrier for the elements array address.
1431 __ mov(scratch_value, value); // Preserve the value which is returned.
1432 __ RecordWrite(elements,
1433 address,
1434 scratch_value,
1435 kLRHasNotBeenSaved,
1436 kDontSaveFPRegs,
1437 EMIT_REMEMBERED_SET,
1438 OMIT_SMI_CHECK);
1439 __ Ret();
1440
1441 __ bind(&fast_double_with_map_check);
1442 // Check for fast double array case. If this fails, call through to the
1443 // runtime.
1444 __ cmp(elements_map,
1445 Operand(masm->isolate()->factory()->fixed_double_array_map()));
1446 __ b(ne, &slow);
1447 __ bind(&fast_double_without_map_check);
1448 __ StoreNumberToDoubleElements(value,
1449 key,
1450 receiver,
1451 elements,
1452 r3,
1453 r4,
1454 r5,
1455 r6,
1456 &transition_double_elements);
1457 __ Ret();
1458
1459 __ bind(&transition_smi_elements);
1460 // Transition the array appropriately depending on the value type.
1461 __ ldr(r4, FieldMemOperand(value, HeapObject::kMapOffset));
1462 __ CompareRoot(r4, Heap::kHeapNumberMapRootIndex);
1463 __ b(ne, &non_double_value);
1464
1465 // Value is a double. Transition FAST_SMI_ONLY_ELEMENTS ->
1466 // FAST_DOUBLE_ELEMENTS and complete the store.
1467 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1468 FAST_DOUBLE_ELEMENTS,
1469 receiver_map,
1470 r4,
1471 &slow);
1472 ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
1473 ElementsTransitionGenerator::GenerateSmiOnlyToDouble(masm, &slow);
1474 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1475 __ jmp(&fast_double_without_map_check);
1476
1477 __ bind(&non_double_value);
1478 // Value is not a double, FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS
1479 __ LoadTransitionedArrayMapConditional(FAST_SMI_ONLY_ELEMENTS,
1480 FAST_ELEMENTS,
1481 receiver_map,
1482 r4,
1483 &slow);
1484 ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
1485 ElementsTransitionGenerator::GenerateSmiOnlyToObject(masm);
1486 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1487 __ jmp(&finish_object_store);
1488
1489 __ bind(&transition_double_elements);
1490 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
1491 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
1492 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1493 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1494 FAST_ELEMENTS,
1495 receiver_map,
1496 r4,
1497 &slow);
1498 ASSERT(receiver_map.is(r3)); // Transition code expects map in r3
1499 ElementsTransitionGenerator::GenerateDoubleToObject(masm, &slow);
1500 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1501 __ jmp(&finish_object_store);
Steve Blocka7e24c12009-10-30 11:49:00 +00001502}
1503
1504
Steve Block1e0659c2011-05-24 12:43:12 +01001505void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001506 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001507 // ----------- S t a t e -------------
1508 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001509 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 // -- r2 : name
1511 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001512 // -----------------------------------
1513
1514 // Get the receiver from the stack and probe the stub cache.
Ben Murdoch589d6972011-11-30 16:04:58 +00001515 Code::Flags flags =
1516 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001517
1518 Isolate::Current()->stub_cache()->GenerateProbe(
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001519 masm, flags, r1, r2, r3, r4, r5, r6);
Steve Blocka7e24c12009-10-30 11:49:00 +00001520
1521 // Cache miss: Jump to runtime.
Leon Clarke4515c472010-02-03 11:58:03 +00001522 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001523}
1524
1525
Leon Clarke4515c472010-02-03 11:58:03 +00001526void StoreIC::GenerateMiss(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001527 // ----------- S t a t e -------------
1528 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001529 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 // -- r2 : name
1531 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001532 // -----------------------------------
1533
Steve Block6ded16b2010-05-10 14:33:55 +01001534 __ Push(r1, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001535
1536 // Perform tail call to the entry.
Steve Block44f0eee2011-05-26 01:26:41 +01001537 ExternalReference ref =
1538 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
Steve Block6ded16b2010-05-10 14:33:55 +01001539 __ TailCallExternalReference(ref, 3, 1);
1540}
1541
1542
1543void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1544 // ----------- S t a t e -------------
1545 // -- r0 : value
1546 // -- r1 : receiver
1547 // -- r2 : name
1548 // -- lr : return address
1549 // -----------------------------------
1550 //
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001551 // This accepts as a receiver anything JSArray::SetElementsLength accepts
1552 // (currently anything except for external arrays which means anything with
1553 // elements of FixedArray type). Value must be a number, but only smis are
1554 // accepted as the most common case.
Steve Block6ded16b2010-05-10 14:33:55 +01001555
1556 Label miss;
1557
1558 Register receiver = r1;
1559 Register value = r0;
1560 Register scratch = r3;
1561
1562 // Check that the receiver isn't a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001563 __ JumpIfSmi(receiver, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001564
1565 // Check that the object is a JS array.
1566 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1567 __ b(ne, &miss);
1568
1569 // Check that elements are FixedArray.
Iain Merrick75681382010-08-19 15:07:18 +01001570 // We rely on StoreIC_ArrayLength below to deal with all types of
1571 // fast elements (including COW).
Steve Block6ded16b2010-05-10 14:33:55 +01001572 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1573 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1574 __ b(ne, &miss);
1575
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001576 // Check that the array has fast properties, otherwise the length
1577 // property might have been redefined.
1578 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kPropertiesOffset));
1579 __ ldr(scratch, FieldMemOperand(scratch, FixedArray::kMapOffset));
1580 __ CompareRoot(scratch, Heap::kHashTableMapRootIndex);
1581 __ b(eq, &miss);
1582
Steve Block6ded16b2010-05-10 14:33:55 +01001583 // Check that value is a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001584 __ JumpIfNotSmi(value, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001585
1586 // Prepare tail call to StoreIC_ArrayLength.
1587 __ Push(receiver, value);
1588
Steve Block44f0eee2011-05-26 01:26:41 +01001589 ExternalReference ref =
1590 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
Steve Block6ded16b2010-05-10 14:33:55 +01001591 __ TailCallExternalReference(ref, 2, 1);
1592
1593 __ bind(&miss);
1594
1595 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001596}
1597
1598
Steve Block8defd9f2010-07-08 12:39:36 +01001599void StoreIC::GenerateNormal(MacroAssembler* masm) {
1600 // ----------- S t a t e -------------
1601 // -- r0 : value
1602 // -- r1 : receiver
1603 // -- r2 : name
1604 // -- lr : return address
1605 // -----------------------------------
1606 Label miss;
1607
1608 GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1609
1610 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
Steve Block44f0eee2011-05-26 01:26:41 +01001611 Counters* counters = masm->isolate()->counters();
1612 __ IncrementCounter(counters->store_normal_hit(),
1613 1, r4, r5);
Steve Block8defd9f2010-07-08 12:39:36 +01001614 __ Ret();
1615
1616 __ bind(&miss);
Steve Block44f0eee2011-05-26 01:26:41 +01001617 __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
Steve Block8defd9f2010-07-08 12:39:36 +01001618 GenerateMiss(masm);
1619}
1620
1621
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001622void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1623 StrictModeFlag strict_mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001624 // ----------- S t a t e -------------
1625 // -- r0 : value
1626 // -- r1 : receiver
1627 // -- r2 : name
1628 // -- lr : return address
1629 // -----------------------------------
1630
1631 __ Push(r1, r2, r0);
1632
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001633 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1634 __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1635 __ Push(r1, r0);
1636
Ben Murdochb0fe1622011-05-05 13:52:32 +01001637 // Do tail-call to runtime routine.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001638 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001639}
1640
1641
Steve Blocka7e24c12009-10-30 11:49:00 +00001642#undef __
1643
1644
Ben Murdochb0fe1622011-05-05 13:52:32 +01001645Condition CompareIC::ComputeCondition(Token::Value op) {
1646 switch (op) {
1647 case Token::EQ_STRICT:
1648 case Token::EQ:
1649 return eq;
1650 case Token::LT:
1651 return lt;
1652 case Token::GT:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001653 return gt;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001654 case Token::LTE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001655 return le;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001656 case Token::GTE:
1657 return ge;
1658 default:
1659 UNREACHABLE();
Steve Block1e0659c2011-05-24 12:43:12 +01001660 return kNoCondition;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001661 }
1662}
1663
1664
1665void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1666 HandleScope scope;
1667 Handle<Code> rewritten;
1668 State previous_state = GetState();
1669 State state = TargetState(previous_state, false, x, y);
1670 if (state == GENERIC) {
1671 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1672 rewritten = stub.GetCode();
1673 } else {
1674 ICCompareStub stub(op_, state);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001675 if (state == KNOWN_OBJECTS) {
1676 stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map()));
1677 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001678 rewritten = stub.GetCode();
1679 }
1680 set_target(*rewritten);
1681
1682#ifdef DEBUG
1683 if (FLAG_trace_ic) {
1684 PrintF("[CompareIC (%s->%s)#%s]\n",
1685 GetStateName(previous_state),
1686 GetStateName(state),
1687 Token::Name(op_));
1688 }
1689#endif
Steve Block1e0659c2011-05-24 12:43:12 +01001690
1691 // Activate inlined smi code.
1692 if (previous_state == UNINITIALIZED) {
1693 PatchInlinedSmiCode(address());
1694 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001695}
1696
1697
1698void PatchInlinedSmiCode(Address address) {
Steve Block1e0659c2011-05-24 12:43:12 +01001699 Address cmp_instruction_address =
1700 address + Assembler::kCallTargetAddressOffset;
1701
1702 // If the instruction following the call is not a cmp rx, #yyy, nothing
1703 // was inlined.
1704 Instr instr = Assembler::instr_at(cmp_instruction_address);
1705 if (!Assembler::IsCmpImmediate(instr)) {
1706 return;
1707 }
1708
1709 // The delta to the start of the map check instruction and the
1710 // condition code uses at the patched jump.
1711 int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1712 delta +=
1713 Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1714 // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1715 // nothing was inlined.
1716 if (delta == 0) {
1717 return;
1718 }
1719
1720#ifdef DEBUG
1721 if (FLAG_trace_ic) {
1722 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
1723 address, cmp_instruction_address, delta);
1724 }
1725#endif
1726
1727 Address patch_address =
1728 cmp_instruction_address - delta * Instruction::kInstrSize;
1729 Instr instr_at_patch = Assembler::instr_at(patch_address);
1730 Instr branch_instr =
1731 Assembler::instr_at(patch_address + Instruction::kInstrSize);
1732 ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1733 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1734 Assembler::GetRm(instr_at_patch).code());
1735 ASSERT(Assembler::IsBranch(branch_instr));
1736 if (Assembler::GetCondition(branch_instr) == eq) {
1737 // This is patching a "jump if not smi" site to be active.
1738 // Changing
1739 // cmp rx, rx
1740 // b eq, <target>
1741 // to
1742 // tst rx, #kSmiTagMask
1743 // b ne, <target>
1744 CodePatcher patcher(patch_address, 2);
1745 Register reg = Assembler::GetRn(instr_at_patch);
1746 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1747 patcher.EmitCondition(ne);
1748 } else {
1749 ASSERT(Assembler::GetCondition(branch_instr) == ne);
1750 // This is patching a "jump if smi" site to be active.
1751 // Changing
1752 // cmp rx, rx
1753 // b ne, <target>
1754 // to
1755 // tst rx, #kSmiTagMask
1756 // b eq, <target>
1757 CodePatcher patcher(patch_address, 2);
1758 Register reg = Assembler::GetRn(instr_at_patch);
1759 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1760 patcher.EmitCondition(eq);
1761 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001762}
1763
1764
Steve Blocka7e24c12009-10-30 11:49:00 +00001765} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001766
1767#endif // V8_TARGET_ARCH_ARM