blob: 6038153a1a76bb200a7d7bd8eadd7746c8f3fb49 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 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));
149 __ tst(scratch1, Operand(PropertyDetails::TypeField::mask() << 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;
197 const int kTypeAndReadOnlyMask
198 = (PropertyDetails::TypeField::mask() |
199 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
200 __ 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);
211 __ RecordWrite(elements, scratch2, scratch1);
Steve Block6ded16b2010-05-10 14:33:55 +0100212}
213
214
Steve Blocka7e24c12009-10-30 11:49:00 +0000215void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
216 // ----------- S t a t e -------------
217 // -- r2 : name
218 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100219 // -- r0 : receiver
220 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 Label miss;
223
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss);
225 __ bind(&miss);
226 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
227}
228
229
Steve Block1e0659c2011-05-24 12:43:12 +0100230void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000231 // ----------- S t a t e -------------
232 // -- r2 : name
233 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100234 // -- r0 : receiver
235 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 // -----------------------------------
237 Label miss;
238
Steve Block1e0659c2011-05-24 12:43:12 +0100239 StubCompiler::GenerateLoadStringLength(masm, r0, r1, r3, &miss,
240 support_wrappers);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 // Cache miss: Jump to runtime.
242 __ bind(&miss);
243 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
244}
245
246
247void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
248 // ----------- S t a t e -------------
249 // -- r2 : name
250 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100251 // -- r0 : receiver
252 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000253 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +0000254 Label miss;
255
Steve Blocka7e24c12009-10-30 11:49:00 +0000256 StubCompiler::GenerateLoadFunctionPrototype(masm, r0, r1, r3, &miss);
257 __ bind(&miss);
258 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
259}
260
261
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100262// Checks the receiver for special cases (value type, slow case bits).
263// Falls through for regular JS object.
264static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
265 Register receiver,
Iain Merrick75681382010-08-19 15:07:18 +0100266 Register map,
267 Register scratch,
Steve Block8defd9f2010-07-08 12:39:36 +0100268 int interceptor_bit,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100269 Label* slow) {
270 // Check that the object isn't a smi.
Steve Block1e0659c2011-05-24 12:43:12 +0100271 __ JumpIfSmi(receiver, slow);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100272 // Get the map of the receiver.
Iain Merrick75681382010-08-19 15:07:18 +0100273 __ ldr(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100274 // Check bit field.
Iain Merrick75681382010-08-19 15:07:18 +0100275 __ ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
276 __ tst(scratch,
Steve Block8defd9f2010-07-08 12:39:36 +0100277 Operand((1 << Map::kIsAccessCheckNeeded) | (1 << interceptor_bit)));
Steve Block1e0659c2011-05-24 12:43:12 +0100278 __ b(ne, slow);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100279 // Check that the object is some kind of JS object EXCEPT JS Value type.
280 // In the case that the object is a value-wrapper object,
281 // we enter the runtime system to make sure that indexing into string
282 // objects work as intended.
283 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
Iain Merrick75681382010-08-19 15:07:18 +0100284 __ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
285 __ cmp(scratch, Operand(JS_OBJECT_TYPE));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100286 __ b(lt, slow);
287}
288
289
290// Loads an indexed element from a fast case array.
Iain Merrick75681382010-08-19 15:07:18 +0100291// If not_fast_array is NULL, doesn't perform the elements map check.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100292static void GenerateFastArrayLoad(MacroAssembler* masm,
293 Register receiver,
294 Register key,
295 Register elements,
296 Register scratch1,
297 Register scratch2,
298 Register result,
299 Label* not_fast_array,
300 Label* out_of_range) {
301 // Register use:
302 //
303 // receiver - holds the receiver on entry.
304 // Unchanged unless 'result' is the same register.
305 //
306 // key - holds the smi key on entry.
307 // Unchanged unless 'result' is the same register.
308 //
309 // elements - holds the elements of the receiver on exit.
310 //
311 // result - holds the result on exit if the load succeeded.
312 // Allowed to be the the same as 'receiver' or 'key'.
313 // Unchanged on bailout so 'receiver' and 'key' can be safely
314 // used by further computation.
315 //
316 // Scratch registers:
317 //
318 // scratch1 - used to hold elements map and elements length.
319 // Holds the elements map if not_fast_array branch is taken.
320 //
321 // scratch2 - used to hold the loaded value.
322
323 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
Iain Merrick75681382010-08-19 15:07:18 +0100324 if (not_fast_array != NULL) {
325 // Check that the object is in fast mode and writable.
326 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
327 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
328 __ cmp(scratch1, ip);
329 __ b(ne, not_fast_array);
330 } else {
331 __ AssertFastElements(elements);
332 }
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100333 // Check that the key (index) is within bounds.
334 __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
335 __ cmp(key, Operand(scratch1));
336 __ b(hs, out_of_range);
337 // Fast case: Do the load.
338 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
339 // The key is a smi.
340 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
341 __ ldr(scratch2,
342 MemOperand(scratch1, key, LSL, kPointerSizeLog2 - kSmiTagSize));
343 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
344 __ cmp(scratch2, ip);
345 // In case the loaded value is the_hole we have to consult GetProperty
346 // to ensure the prototype chain is searched.
347 __ b(eq, out_of_range);
348 __ mov(result, scratch2);
349}
350
351
352// Checks whether a key is an array index string or a symbol string.
353// Falls through if a key is a symbol.
354static void GenerateKeyStringCheck(MacroAssembler* masm,
355 Register key,
356 Register map,
357 Register hash,
358 Label* index_string,
359 Label* not_symbol) {
360 // The key is not a smi.
361 // Is it a string?
362 __ CompareObjectType(key, map, hash, FIRST_NONSTRING_TYPE);
363 __ b(ge, not_symbol);
364
365 // Is the string an array index, with cached numeric value?
366 __ ldr(hash, FieldMemOperand(key, String::kHashFieldOffset));
367 __ tst(hash, Operand(String::kContainsCachedArrayIndexMask));
368 __ b(eq, index_string);
369
370 // Is the string a symbol?
371 // map: key map
372 __ ldrb(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
373 ASSERT(kSymbolTag != 0);
374 __ tst(hash, Operand(kIsSymbolMask));
375 __ b(eq, not_symbol);
376}
377
378
Steve Blocka7e24c12009-10-30 11:49:00 +0000379// Defined in ic.cc.
380Object* CallIC_Miss(Arguments args);
381
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100382// The generated code does not accept smi keys.
383// The generated code falls through if both probes miss.
384static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
385 int argc,
Ben Murdoch257744e2011-11-30 15:57:28 +0000386 Code::Kind kind,
387 Code::ExtraICState extra_ic_state) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 // ----------- S t a t e -------------
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100389 // -- r1 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +0000390 // -- r2 : name
Steve Blocka7e24c12009-10-30 11:49:00 +0000391 // -----------------------------------
392 Label number, non_number, non_string, boolean, probe, miss;
393
Steve Blocka7e24c12009-10-30 11:49:00 +0000394 // Probe the stub cache.
Ben Murdochb8e0da22011-05-16 14:20:40 +0100395 Code::Flags flags = Code::ComputeFlags(kind,
396 NOT_IN_LOOP,
397 MONOMORPHIC,
Ben Murdoch257744e2011-11-30 15:57:28 +0000398 extra_ic_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(
402 masm, flags, r1, r2, r3, r4, r5);
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(
441 masm, flags, r1, r2, r3, r4, r5);
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
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100467static void GenerateCallNormal(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 Murdoch257744e2011-11-30 15:57:28 +0000489static void GenerateCallMiss(MacroAssembler* masm,
490 int argc,
491 IC::UtilityId id,
492 Code::ExtraICState extra_ic_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
508 __ EnterInternalFrame();
509
510 // Push the receiver and the name of the function.
Steve Block6ded16b2010-05-10 14:33:55 +0100511 __ Push(r3, r2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000512
513 // Call the entry.
514 __ mov(r0, Operand(2));
Steve Block44f0eee2011-05-26 01:26:41 +0100515 __ mov(r1, Operand(ExternalReference(IC_Utility(id), isolate)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000516
517 CEntryStub stub(1);
518 __ CallStub(&stub);
519
520 // Move result to r1 and leave the internal frame.
521 __ mov(r1, Operand(r0));
522 __ LeaveInternalFrame();
523
524 // Check if the receiver is a global object of some sort.
Steve Block8defd9f2010-07-08 12:39:36 +0100525 // This can happen only for regular CallIC but not KeyedCallIC.
526 if (id == IC::kCallIC_Miss) {
527 Label invoke, global;
528 __ ldr(r2, MemOperand(sp, argc * kPointerSize)); // receiver
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000529 __ JumpIfSmi(r2, &invoke);
Steve Block8defd9f2010-07-08 12:39:36 +0100530 __ CompareObjectType(r2, r3, r3, JS_GLOBAL_OBJECT_TYPE);
531 __ b(eq, &global);
532 __ cmp(r3, Operand(JS_BUILTINS_OBJECT_TYPE));
533 __ b(ne, &invoke);
Steve Blocka7e24c12009-10-30 11:49:00 +0000534
Steve Block8defd9f2010-07-08 12:39:36 +0100535 // Patch the receiver on the stack.
536 __ bind(&global);
537 __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
538 __ str(r2, MemOperand(sp, argc * kPointerSize));
539 __ bind(&invoke);
540 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000541
542 // Invoke the function.
Ben Murdoch257744e2011-11-30 15:57:28 +0000543 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
544 ? CALL_AS_FUNCTION
545 : CALL_AS_METHOD;
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 ParameterCount actual(argc);
Ben Murdoch257744e2011-11-30 15:57:28 +0000547 __ InvokeFunction(r1,
548 actual,
549 JUMP_FUNCTION,
550 NullCallWrapper(),
551 call_kind);
Steve Blocka7e24c12009-10-30 11:49:00 +0000552}
553
554
Ben Murdoch257744e2011-11-30 15:57:28 +0000555void CallIC::GenerateMiss(MacroAssembler* masm,
556 int argc,
557 Code::ExtraICState extra_ic_state) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100558 // ----------- S t a t e -------------
559 // -- r2 : name
560 // -- lr : return address
561 // -----------------------------------
562
Ben Murdoch257744e2011-11-30 15:57:28 +0000563 GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100564}
565
566
Ben Murdoch257744e2011-11-30 15:57:28 +0000567void CallIC::GenerateMegamorphic(MacroAssembler* masm,
568 int argc,
569 Code::ExtraICState extra_ic_state) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100570 // ----------- S t a t e -------------
571 // -- r2 : name
572 // -- lr : return address
573 // -----------------------------------
574
575 // Get the receiver of the function from the stack into r1.
576 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
Ben Murdoch257744e2011-11-30 15:57:28 +0000577 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
578 GenerateMiss(masm, argc, extra_ic_state);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100579}
580
581
582void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
583 // ----------- S t a t e -------------
584 // -- r2 : name
585 // -- lr : return address
586 // -----------------------------------
587
588 GenerateCallNormal(masm, argc);
Ben Murdoch257744e2011-11-30 15:57:28 +0000589 GenerateMiss(masm, argc, Code::kNoExtraICState);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100590}
591
592
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100593void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100594 // ----------- S t a t e -------------
595 // -- r2 : name
596 // -- lr : return address
597 // -----------------------------------
598
Ben Murdoch257744e2011-11-30 15:57:28 +0000599 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100600}
601
602
603void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100604 // ----------- S t a t e -------------
605 // -- r2 : name
606 // -- lr : return address
607 // -----------------------------------
608
609 // Get the receiver of the function from the stack into r1.
610 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
611
612 Label do_call, slow_call, slow_load, slow_reload_receiver;
613 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
614 Label index_smi, index_string;
615
616 // Check that the key is a smi.
Steve Block1e0659c2011-05-24 12:43:12 +0100617 __ JumpIfNotSmi(r2, &check_string);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100618 __ bind(&index_smi);
619 // Now the key is known to be a smi. This place is also jumped to from below
620 // where a numeric string is converted to a smi.
621
Steve Block8defd9f2010-07-08 12:39:36 +0100622 GenerateKeyedLoadReceiverCheck(
623 masm, r1, r0, r3, Map::kHasIndexedInterceptor, &slow_call);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100624
625 GenerateFastArrayLoad(
626 masm, r1, r2, r4, r3, r0, r1, &check_number_dictionary, &slow_load);
Steve Block44f0eee2011-05-26 01:26:41 +0100627 Counters* counters = masm->isolate()->counters();
628 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100629
630 __ bind(&do_call);
631 // receiver in r1 is not used after this point.
632 // r2: key
633 // r1: function
Steve Block8defd9f2010-07-08 12:39:36 +0100634 GenerateFunctionTailCall(masm, argc, &slow_call, r0);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100635
636 __ bind(&check_number_dictionary);
637 // r2: key
638 // r3: elements map
639 // r4: elements
640 // Check whether the elements is a number dictionary.
641 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
642 __ cmp(r3, ip);
643 __ b(ne, &slow_load);
644 __ mov(r0, Operand(r2, ASR, kSmiTagSize));
645 // r0: untagged index
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000646 __ LoadFromNumberDictionary(&slow_load, r4, r2, r1, r0, r3, r5);
Steve Block44f0eee2011-05-26 01:26:41 +0100647 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100648 __ jmp(&do_call);
649
650 __ bind(&slow_load);
651 // This branch is taken when calling KeyedCallIC_Miss is neither required
652 // nor beneficial.
Steve Block44f0eee2011-05-26 01:26:41 +0100653 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100654 __ EnterInternalFrame();
655 __ push(r2); // save the key
656 __ Push(r1, r2); // pass the receiver and the key
657 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
658 __ pop(r2); // restore the key
659 __ LeaveInternalFrame();
660 __ mov(r1, r0);
661 __ jmp(&do_call);
662
663 __ bind(&check_string);
664 GenerateKeyStringCheck(masm, r2, r0, r3, &index_string, &slow_call);
665
666 // The key is known to be a symbol.
667 // If the receiver is a regular JS object with slow properties then do
668 // a quick inline probe of the receiver's dictionary.
669 // Otherwise do the monomorphic cache probe.
Steve Block8defd9f2010-07-08 12:39:36 +0100670 GenerateKeyedLoadReceiverCheck(
671 masm, r1, r0, r3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100672
Steve Block8defd9f2010-07-08 12:39:36 +0100673 __ ldr(r0, FieldMemOperand(r1, JSObject::kPropertiesOffset));
674 __ ldr(r3, FieldMemOperand(r0, HeapObject::kMapOffset));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100675 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
676 __ cmp(r3, ip);
677 __ b(ne, &lookup_monomorphic_cache);
678
Steve Block8defd9f2010-07-08 12:39:36 +0100679 GenerateDictionaryLoad(masm, &slow_load, r0, r2, r1, r3, r4);
Steve Block44f0eee2011-05-26 01:26:41 +0100680 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100681 __ jmp(&do_call);
682
683 __ bind(&lookup_monomorphic_cache);
Steve Block44f0eee2011-05-26 01:26:41 +0100684 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, r0, r3);
Ben Murdoch257744e2011-11-30 15:57:28 +0000685 GenerateMonomorphicCacheProbe(masm,
686 argc,
687 Code::KEYED_CALL_IC,
688 Code::kNoExtraICState);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100689 // Fall through on miss.
690
691 __ bind(&slow_call);
692 // This branch is taken if:
693 // - the receiver requires boxing or access check,
694 // - the key is neither smi nor symbol,
695 // - the value loaded is not a function,
696 // - there is hope that the runtime will create a monomorphic call stub
697 // that will get fetched next time.
Steve Block44f0eee2011-05-26 01:26:41 +0100698 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, r0, r3);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100699 GenerateMiss(masm, argc);
700
701 __ bind(&index_string);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100702 __ IndexFromHash(r3, r2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100703 // Now jump to the place where smi keys are handled.
704 __ jmp(&index_smi);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100705}
706
707
708void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100709 // ----------- S t a t e -------------
710 // -- r2 : name
711 // -- lr : return address
712 // -----------------------------------
713
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100714 // Check if the name is a string.
715 Label miss;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000716 __ JumpIfSmi(r2, &miss);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100717 __ IsObjectJSStringType(r2, r0, &miss);
718
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100719 GenerateCallNormal(masm, argc);
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100720 __ bind(&miss);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100721 GenerateMiss(masm, argc);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100722}
723
724
Steve Blocka7e24c12009-10-30 11:49:00 +0000725// Defined in ic.cc.
726Object* LoadIC_Miss(Arguments args);
727
728void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
729 // ----------- S t a t e -------------
730 // -- r2 : name
731 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100732 // -- r0 : receiver
733 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 // -----------------------------------
735
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 // Probe the stub cache.
737 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
738 NOT_IN_LOOP,
739 MONOMORPHIC);
Steve Block44f0eee2011-05-26 01:26:41 +0100740 Isolate::Current()->stub_cache()->GenerateProbe(
741 masm, flags, r0, r2, r3, r4, r5);
Steve Blocka7e24c12009-10-30 11:49:00 +0000742
743 // Cache miss: Jump to runtime.
Andrei Popescu402d9372010-02-26 13:31:12 +0000744 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000745}
746
747
748void LoadIC::GenerateNormal(MacroAssembler* masm) {
749 // ----------- S t a t e -------------
750 // -- r2 : name
751 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100752 // -- r0 : receiver
753 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000754 // -----------------------------------
Steve Block8defd9f2010-07-08 12:39:36 +0100755 Label miss;
Steve Blocka7e24c12009-10-30 11:49:00 +0000756
Steve Block8defd9f2010-07-08 12:39:36 +0100757 GenerateStringDictionaryReceiverCheck(masm, r0, r1, r3, r4, &miss);
Steve Blocka7e24c12009-10-30 11:49:00 +0000758
Steve Block8defd9f2010-07-08 12:39:36 +0100759 // r1: elements
760 GenerateDictionaryLoad(masm, &miss, r1, r2, r0, r3, r4);
Steve Blocka7e24c12009-10-30 11:49:00 +0000761 __ Ret();
762
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100763 // Cache miss: Jump to runtime.
Steve Blocka7e24c12009-10-30 11:49:00 +0000764 __ bind(&miss);
Andrei Popescu402d9372010-02-26 13:31:12 +0000765 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +0000766}
767
768
769void LoadIC::GenerateMiss(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 // ----------- S t a t e -------------
771 // -- r2 : name
772 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100773 // -- r0 : receiver
774 // -- sp[0] : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100776 Isolate* isolate = masm->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000777
Steve Block44f0eee2011-05-26 01:26:41 +0100778 __ IncrementCounter(isolate->counters()->load_miss(), 1, r3, r4);
Steve Block8defd9f2010-07-08 12:39:36 +0100779
Steve Block6ded16b2010-05-10 14:33:55 +0100780 __ mov(r3, r0);
781 __ Push(r3, r2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000782
783 // Perform tail call to the entry.
Steve Block44f0eee2011-05-26 01:26:41 +0100784 ExternalReference ref =
785 ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
Steve Block6ded16b2010-05-10 14:33:55 +0100786 __ TailCallExternalReference(ref, 2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000787}
788
Steve Block053d10c2011-06-13 19:13:29 +0100789
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000790static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
791 Register object,
792 Register key,
793 Register scratch1,
794 Register scratch2,
795 Register scratch3,
796 Label* unmapped_case,
797 Label* slow_case) {
798 Heap* heap = masm->isolate()->heap();
799
800 // Check that the receiver is a JSObject. Because of the map check
801 // later, we do not need to check for interceptors or whether it
802 // requires access checks.
803 __ JumpIfSmi(object, slow_case);
804 // Check that the object is some kind of JSObject.
805 __ CompareObjectType(object, scratch1, scratch2, FIRST_JS_RECEIVER_TYPE);
806 __ b(lt, slow_case);
807
808 // Check that the key is a positive smi.
809 __ tst(key, Operand(0x8000001));
810 __ b(ne, slow_case);
811
812 // Load the elements into scratch1 and check its map.
813 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
814 __ ldr(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
815 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
816
817 // Check if element is in the range of mapped arguments. If not, jump
818 // to the unmapped lookup with the parameter map in scratch1.
819 __ ldr(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
820 __ sub(scratch2, scratch2, Operand(Smi::FromInt(2)));
821 __ cmp(key, Operand(scratch2));
822 __ b(cs, unmapped_case);
823
824 // Load element index and check whether it is the hole.
825 const int kOffset =
826 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
827
828 __ mov(scratch3, Operand(kPointerSize >> 1));
829 __ mul(scratch3, key, scratch3);
830 __ add(scratch3, scratch3, Operand(kOffset));
831
832 __ ldr(scratch2, MemOperand(scratch1, scratch3));
833 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
834 __ cmp(scratch2, scratch3);
835 __ b(eq, unmapped_case);
836
837 // Load value from context and return it. We can reuse scratch1 because
838 // we do not jump to the unmapped lookup (which requires the parameter
839 // map in scratch1).
840 __ ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
841 __ mov(scratch3, Operand(kPointerSize >> 1));
842 __ mul(scratch3, scratch2, scratch3);
843 __ add(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
844 return MemOperand(scratch1, scratch3);
845}
846
847
848static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
849 Register key,
850 Register parameter_map,
851 Register scratch,
852 Label* slow_case) {
853 // Element is in arguments backing store, which is referenced by the
854 // second element of the parameter_map. The parameter_map register
855 // must be loaded with the parameter map of the arguments object and is
856 // overwritten.
857 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
858 Register backing_store = parameter_map;
859 __ ldr(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
860 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
861 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
862 DONT_DO_SMI_CHECK);
863 __ ldr(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
864 __ cmp(key, Operand(scratch));
865 __ b(cs, slow_case);
866 __ mov(scratch, Operand(kPointerSize >> 1));
867 __ mul(scratch, key, scratch);
868 __ add(scratch,
869 scratch,
870 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
871 return MemOperand(backing_store, scratch);
872}
873
874
875void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
876 // ---------- S t a t e --------------
877 // -- lr : return address
878 // -- r0 : key
879 // -- r1 : receiver
880 // -----------------------------------
881 Label slow, notin;
882 MemOperand mapped_location =
883 GenerateMappedArgumentsLookup(masm, r1, r0, r2, r3, r4, &notin, &slow);
884 __ ldr(r0, mapped_location);
885 __ Ret();
886 __ bind(&notin);
887 // The unmapped lookup expects that the parameter map is in r2.
888 MemOperand unmapped_location =
889 GenerateUnmappedArgumentsLookup(masm, r0, r2, r3, &slow);
890 __ ldr(r2, unmapped_location);
891 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
892 __ cmp(r2, r3);
893 __ b(eq, &slow);
894 __ mov(r0, r2);
895 __ Ret();
896 __ bind(&slow);
897 GenerateMiss(masm, false);
898}
899
900
901void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
902 // ---------- S t a t e --------------
903 // -- r0 : value
904 // -- r1 : key
905 // -- r2 : receiver
906 // -- lr : return address
907 // -----------------------------------
908 Label slow, notin;
909 MemOperand mapped_location =
910 GenerateMappedArgumentsLookup(masm, r2, r1, r3, r4, r5, &notin, &slow);
911 __ str(r0, mapped_location);
912 __ add(r6, r3, r5);
913 __ RecordWrite(r3, r6, r9);
914 __ Ret();
915 __ bind(&notin);
916 // The unmapped lookup expects that the parameter map is in r3.
917 MemOperand unmapped_location =
918 GenerateUnmappedArgumentsLookup(masm, r1, r3, r4, &slow);
919 __ str(r0, unmapped_location);
920 __ add(r6, r3, r4);
921 __ RecordWrite(r3, r6, r9);
922 __ Ret();
923 __ bind(&slow);
924 GenerateMiss(masm, false);
925}
926
927
928void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
929 int argc) {
930 // ----------- S t a t e -------------
931 // -- r2 : name
932 // -- lr : return address
933 // -----------------------------------
934 Label slow, notin;
935 // Load receiver.
936 __ ldr(r1, MemOperand(sp, argc * kPointerSize));
937 MemOperand mapped_location =
938 GenerateMappedArgumentsLookup(masm, r1, r2, r3, r4, r5, &notin, &slow);
939 __ ldr(r1, mapped_location);
940 GenerateFunctionTailCall(masm, argc, &slow, r3);
941 __ bind(&notin);
942 // The unmapped lookup expects that the parameter map is in r3.
943 MemOperand unmapped_location =
944 GenerateUnmappedArgumentsLookup(masm, r2, r3, r4, &slow);
945 __ ldr(r1, unmapped_location);
946 __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
947 __ cmp(r1, r3);
948 __ b(eq, &slow);
949 GenerateFunctionTailCall(masm, argc, &slow, r3);
950 __ bind(&slow);
951 GenerateMiss(masm, argc);
952}
953
954
955Object* KeyedLoadIC_Miss(Arguments args);
956
957
Ben Murdoch257744e2011-11-30 15:57:28 +0000958void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 // ---------- S t a t e --------------
960 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100961 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +0100962 // -- r1 : receiver
Leon Clarke4515c472010-02-03 11:58:03 +0000963 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +0100964 Isolate* isolate = masm->isolate();
Leon Clarke4515c472010-02-03 11:58:03 +0000965
Steve Block44f0eee2011-05-26 01:26:41 +0100966 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, r3, r4);
Steve Block8defd9f2010-07-08 12:39:36 +0100967
Steve Block6ded16b2010-05-10 14:33:55 +0100968 __ Push(r1, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000969
Ben Murdoch257744e2011-11-30 15:57:28 +0000970 // Perform tail call to the entry.
971 ExternalReference ref = force_generic
972 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
973 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
974
Steve Block6ded16b2010-05-10 14:33:55 +0100975 __ TailCallExternalReference(ref, 2, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +0000976}
977
978
979void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
980 // ---------- S t a t e --------------
981 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100982 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +0100983 // -- r1 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +0000984 // -----------------------------------
985
Steve Block6ded16b2010-05-10 14:33:55 +0100986 __ Push(r1, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +0000987
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100988 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000989}
990
991
992void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
993 // ---------- S t a t e --------------
994 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +0100995 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +0100996 // -- r1 : receiver
Leon Clarke4515c472010-02-03 11:58:03 +0000997 // -----------------------------------
Ben Murdochbb769b22010-08-11 14:56:33 +0100998 Label slow, check_string, index_smi, index_string, property_array_property;
Steve Block44f0eee2011-05-26 01:26:41 +0100999 Label probe_dictionary, check_number_dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00001000
Kristian Monsen25f61362010-05-21 11:50:48 +01001001 Register key = r0;
1002 Register receiver = r1;
Steve Blocka7e24c12009-10-30 11:49:00 +00001003
Steve Block44f0eee2011-05-26 01:26:41 +01001004 Isolate* isolate = masm->isolate();
1005
Andrei Popescu402d9372010-02-26 13:31:12 +00001006 // Check that the key is a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001007 __ JumpIfNotSmi(key, &check_string);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001008 __ bind(&index_smi);
1009 // Now the key is known to be a smi. This place is also jumped to from below
1010 // where a numeric string is converted to a smi.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001011
Steve Block8defd9f2010-07-08 12:39:36 +01001012 GenerateKeyedLoadReceiverCheck(
1013 masm, receiver, r2, r3, Map::kHasIndexedInterceptor, &slow);
1014
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001015 // Check the receiver's map to see if it has fast elements.
1016 __ CheckFastElements(r2, r3, &check_number_dictionary);
Iain Merrick75681382010-08-19 15:07:18 +01001017
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001018 GenerateFastArrayLoad(
Iain Merrick75681382010-08-19 15:07:18 +01001019 masm, receiver, key, r4, r3, r2, r0, NULL, &slow);
Steve Block44f0eee2011-05-26 01:26:41 +01001020 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r2, r3);
Steve Blocka7e24c12009-10-30 11:49:00 +00001021 __ Ret();
Steve Block6ded16b2010-05-10 14:33:55 +01001022
Steve Block6ded16b2010-05-10 14:33:55 +01001023 __ bind(&check_number_dictionary);
Steve Block44f0eee2011-05-26 01:26:41 +01001024 __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
1025 __ ldr(r3, FieldMemOperand(r4, JSObject::kMapOffset));
1026
Steve Block6ded16b2010-05-10 14:33:55 +01001027 // Check whether the elements is a number dictionary.
Kristian Monsen25f61362010-05-21 11:50:48 +01001028 // r0: key
Kristian Monsen25f61362010-05-21 11:50:48 +01001029 // r3: elements map
1030 // r4: elements
Steve Block6ded16b2010-05-10 14:33:55 +01001031 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
1032 __ cmp(r3, ip);
1033 __ b(ne, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001034 __ mov(r2, Operand(r0, ASR, kSmiTagSize));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001035 __ LoadFromNumberDictionary(&slow, r4, r0, r0, r2, r3, r5);
Steve Block6ded16b2010-05-10 14:33:55 +01001036 __ Ret();
1037
Kristian Monsen25f61362010-05-21 11:50:48 +01001038 // Slow case, key and receiver still in r0 and r1.
Steve Block6ded16b2010-05-10 14:33:55 +01001039 __ bind(&slow);
Steve Block44f0eee2011-05-26 01:26:41 +01001040 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
1041 1, r2, r3);
Steve Block6ded16b2010-05-10 14:33:55 +01001042 GenerateRuntimeGetProperty(masm);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001043
1044 __ bind(&check_string);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001045 GenerateKeyStringCheck(masm, key, r2, r3, &index_string, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001046
Steve Block8defd9f2010-07-08 12:39:36 +01001047 GenerateKeyedLoadReceiverCheck(
1048 masm, receiver, r2, r3, Map::kHasNamedInterceptor, &slow);
1049
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001050 // If the receiver is a fast-case object, check the keyed lookup
1051 // cache. Otherwise probe the dictionary.
1052 __ ldr(r3, FieldMemOperand(r1, JSObject::kPropertiesOffset));
Steve Block8defd9f2010-07-08 12:39:36 +01001053 __ ldr(r4, FieldMemOperand(r3, HeapObject::kMapOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001054 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
Steve Block8defd9f2010-07-08 12:39:36 +01001055 __ cmp(r4, ip);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001056 __ b(eq, &probe_dictionary);
1057
1058 // Load the map of the receiver, compute the keyed lookup cache hash
1059 // based on 32 bits of the map pointer and the string hash.
1060 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1061 __ mov(r3, Operand(r2, ASR, KeyedLookupCache::kMapHashShift));
1062 __ ldr(r4, FieldMemOperand(r0, String::kHashFieldOffset));
1063 __ eor(r3, r3, Operand(r4, ASR, String::kHashShift));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001064 __ And(r3, r3, Operand(KeyedLookupCache::kCapacityMask));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001065
1066 // Load the key (consisting of map and symbol) from the cache and
1067 // check for match.
Steve Block44f0eee2011-05-26 01:26:41 +01001068 ExternalReference cache_keys =
1069 ExternalReference::keyed_lookup_cache_keys(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001070 __ mov(r4, Operand(cache_keys));
1071 __ add(r4, r4, Operand(r3, LSL, kPointerSizeLog2 + 1));
1072 __ ldr(r5, MemOperand(r4, kPointerSize, PostIndex)); // Move r4 to symbol.
1073 __ cmp(r2, r5);
1074 __ b(ne, &slow);
1075 __ ldr(r5, MemOperand(r4));
1076 __ cmp(r0, r5);
1077 __ b(ne, &slow);
1078
Ben Murdochbb769b22010-08-11 14:56:33 +01001079 // Get field offset.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001080 // r0 : key
1081 // r1 : receiver
1082 // r2 : receiver's map
1083 // r3 : lookup cache index
Steve Block44f0eee2011-05-26 01:26:41 +01001084 ExternalReference cache_field_offsets =
1085 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001086 __ mov(r4, Operand(cache_field_offsets));
1087 __ ldr(r5, MemOperand(r4, r3, LSL, kPointerSizeLog2));
1088 __ ldrb(r6, FieldMemOperand(r2, Map::kInObjectPropertiesOffset));
Ben Murdochbb769b22010-08-11 14:56:33 +01001089 __ sub(r5, r5, r6, SetCC);
1090 __ b(ge, &property_array_property);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001091
1092 // Load in-object property.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001093 __ ldrb(r6, FieldMemOperand(r2, Map::kInstanceSizeOffset));
1094 __ add(r6, r6, r5); // Index from start of object.
1095 __ sub(r1, r1, Operand(kHeapObjectTag)); // Remove the heap tag.
1096 __ ldr(r0, MemOperand(r1, r6, LSL, kPointerSizeLog2));
Steve Block44f0eee2011-05-26 01:26:41 +01001097 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1098 1, r2, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001099 __ Ret();
1100
Ben Murdochbb769b22010-08-11 14:56:33 +01001101 // Load property array property.
1102 __ bind(&property_array_property);
1103 __ ldr(r1, FieldMemOperand(r1, JSObject::kPropertiesOffset));
1104 __ add(r1, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1105 __ ldr(r0, MemOperand(r1, r5, LSL, kPointerSizeLog2));
Steve Block44f0eee2011-05-26 01:26:41 +01001106 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1107 1, r2, r3);
Ben Murdochbb769b22010-08-11 14:56:33 +01001108 __ Ret();
1109
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001110 // Do a quick inline probe of the receiver's dictionary, if it
1111 // exists.
1112 __ bind(&probe_dictionary);
Steve Block8defd9f2010-07-08 12:39:36 +01001113 // r1: receiver
1114 // r0: key
1115 // r3: elements
1116 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1117 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
1118 GenerateGlobalInstanceTypeCheck(masm, r2, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001119 // Load the property to r0.
Steve Block8defd9f2010-07-08 12:39:36 +01001120 GenerateDictionaryLoad(masm, &slow, r3, r0, r0, r2, r4);
Steve Block44f0eee2011-05-26 01:26:41 +01001121 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1122 1, r2, r3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001123 __ Ret();
1124
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001125 __ bind(&index_string);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001126 __ IndexFromHash(r3, key);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001127 // Now jump to the place where smi keys are handled.
1128 __ jmp(&index_smi);
Steve Blocka7e24c12009-10-30 11:49:00 +00001129}
1130
1131
Leon Clarkee46be812010-01-19 14:06:41 +00001132void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
1133 // ---------- S t a t e --------------
1134 // -- lr : return address
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001135 // -- r0 : key (index)
Kristian Monsen25f61362010-05-21 11:50:48 +01001136 // -- r1 : receiver
Leon Clarke4515c472010-02-03 11:58:03 +00001137 // -----------------------------------
Steve Block6ded16b2010-05-10 14:33:55 +01001138 Label miss;
Leon Clarke4515c472010-02-03 11:58:03 +00001139
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001140 Register receiver = r1;
Steve Block6ded16b2010-05-10 14:33:55 +01001141 Register index = r0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001142 Register scratch1 = r2;
1143 Register scratch2 = r3;
1144 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,
1148 scratch1,
1149 scratch2,
1150 result,
1151 &miss, // When not a string.
1152 &miss, // When not a number.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001153 &miss, // When index out of range.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001154 STRING_INDEX_IS_ARRAY_INDEX);
1155 char_at_generator.GenerateFast(masm);
1156 __ Ret();
Steve Block6ded16b2010-05-10 14:33:55 +01001157
Ben Murdochb0fe1622011-05-05 13:52:32 +01001158 StubRuntimeCallHelper call_helper;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001159 char_at_generator.GenerateSlow(masm, call_helper);
Steve Block6ded16b2010-05-10 14:33:55 +01001160
Steve Block6ded16b2010-05-10 14:33:55 +01001161 __ bind(&miss);
Ben Murdoch257744e2011-11-30 15:57:28 +00001162 GenerateMiss(masm, false);
Leon Clarkee46be812010-01-19 14:06:41 +00001163}
1164
1165
Andrei Popescu402d9372010-02-26 13:31:12 +00001166void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
1167 // ---------- S t a t e --------------
1168 // -- lr : return address
Steve Block6ded16b2010-05-10 14:33:55 +01001169 // -- r0 : key
Kristian Monsen25f61362010-05-21 11:50:48 +01001170 // -- r1 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +00001171 // -----------------------------------
1172 Label slow;
1173
Andrei Popescu402d9372010-02-26 13:31:12 +00001174 // Check that the receiver isn't a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001175 __ JumpIfSmi(r1, &slow);
Andrei Popescu402d9372010-02-26 13:31:12 +00001176
Ben Murdochf87a2032010-10-22 12:50:53 +01001177 // Check that the key is an array index, that is Uint32.
1178 __ tst(r0, Operand(kSmiTagMask | kSmiSignMask));
1179 __ b(ne, &slow);
Andrei Popescu402d9372010-02-26 13:31:12 +00001180
1181 // Get the map of the receiver.
1182 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
1183
1184 // Check that it has indexed interceptor and access checks
1185 // are not enabled for this object.
1186 __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
1187 __ and_(r3, r3, Operand(kSlowCaseBitFieldMask));
1188 __ cmp(r3, Operand(1 << Map::kHasIndexedInterceptor));
1189 __ b(ne, &slow);
1190
1191 // Everything is fine, call runtime.
Steve Block6ded16b2010-05-10 14:33:55 +01001192 __ Push(r1, r0); // Receiver, key.
Andrei Popescu402d9372010-02-26 13:31:12 +00001193
1194 // Perform tail call to the entry.
Steve Block44f0eee2011-05-26 01:26:41 +01001195 __ TailCallExternalReference(
1196 ExternalReference(IC_Utility(kKeyedLoadPropertyWithInterceptor),
1197 masm->isolate()),
1198 2,
1199 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001200
1201 __ bind(&slow);
Ben Murdoch257744e2011-11-30 15:57:28 +00001202 GenerateMiss(masm, false);
Andrei Popescu402d9372010-02-26 13:31:12 +00001203}
1204
1205
Ben Murdoch257744e2011-11-30 15:57:28 +00001206void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 // ---------- S t a t e --------------
1208 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001209 // -- r1 : key
1210 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001211 // -- lr : return address
Leon Clarke4515c472010-02-03 11:58:03 +00001212 // -----------------------------------
Steve Blocka7e24c12009-10-30 11:49:00 +00001213
Leon Clarkef7060e22010-06-03 12:02:55 +01001214 // Push receiver, key and value for runtime call.
1215 __ Push(r2, r1, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001216
Ben Murdoch257744e2011-11-30 15:57:28 +00001217 ExternalReference ref = force_generic
1218 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1219 masm->isolate())
1220 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1221 __ TailCallExternalReference(ref, 3, 1);
1222}
1223
1224
1225void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
1226 // ---------- S t a t e --------------
1227 // -- r0 : value
1228 // -- r1 : key
1229 // -- r2 : receiver
1230 // -- lr : return address
1231 // -----------------------------------
1232
1233 // Push receiver, key and value for runtime call.
1234 __ Push(r2, r1, r0);
1235
1236 // The slow case calls into the runtime to complete the store without causing
1237 // an IC miss that would otherwise cause a transition to the generic stub.
Steve Block44f0eee2011-05-26 01:26:41 +01001238 ExternalReference ref =
Ben Murdoch257744e2011-11-30 15:57:28 +00001239 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
Steve Block6ded16b2010-05-10 14:33:55 +01001240 __ TailCallExternalReference(ref, 3, 1);
Andrei Popescu402d9372010-02-26 13:31:12 +00001241}
1242
1243
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001244void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1245 StrictModeFlag strict_mode) {
Andrei Popescu402d9372010-02-26 13:31:12 +00001246 // ---------- S t a t e --------------
1247 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001248 // -- r1 : key
1249 // -- r2 : receiver
Andrei Popescu402d9372010-02-26 13:31:12 +00001250 // -- lr : return address
Andrei Popescu402d9372010-02-26 13:31:12 +00001251 // -----------------------------------
Leon Clarkef7060e22010-06-03 12:02:55 +01001252
1253 // Push receiver, key and value for runtime call.
1254 __ Push(r2, r1, r0);
Andrei Popescu402d9372010-02-26 13:31:12 +00001255
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001256 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1257 __ mov(r0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1258 __ Push(r1, r0);
1259
1260 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001261}
1262
1263
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001264void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1265 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 // ---------- S t a t e --------------
1267 // -- r0 : value
Leon Clarkef7060e22010-06-03 12:02:55 +01001268 // -- r1 : key
1269 // -- r2 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 // -- lr : return address
Leon Clarke4515c472010-02-03 11:58:03 +00001271 // -----------------------------------
Steve Block44f0eee2011-05-26 01:26:41 +01001272 Label slow, fast, array, extra;
Leon Clarke4515c472010-02-03 11:58:03 +00001273
Leon Clarkef7060e22010-06-03 12:02:55 +01001274 // Register usage.
1275 Register value = r0;
1276 Register key = r1;
1277 Register receiver = r2;
1278 Register elements = r3; // Elements array of the receiver.
1279 // r4 and r5 are used as general scratch registers.
1280
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 // Check that the key is a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001282 __ JumpIfNotSmi(key, &slow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001283 // Check that the object isn't a smi.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001284 __ JumpIfSmi(receiver, &slow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 // Get the map of the object.
Leon Clarkef7060e22010-06-03 12:02:55 +01001286 __ ldr(r4, FieldMemOperand(receiver, HeapObject::kMapOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 // Check that the receiver does not require access checks. We need
1288 // to do this because this generic stub does not perform map checks.
Leon Clarkef7060e22010-06-03 12:02:55 +01001289 __ ldrb(ip, FieldMemOperand(r4, Map::kBitFieldOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001290 __ tst(ip, Operand(1 << Map::kIsAccessCheckNeeded));
1291 __ b(ne, &slow);
1292 // Check if the object is a JS array or not.
Leon Clarkef7060e22010-06-03 12:02:55 +01001293 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset));
1294 __ cmp(r4, Operand(JS_ARRAY_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +00001295 __ b(eq, &array);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001296 // Check that the object is some kind of JSObject.
1297 __ cmp(r4, Operand(FIRST_JS_RECEIVER_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +00001298 __ b(lt, &slow);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001299 __ cmp(r4, Operand(JS_PROXY_TYPE));
1300 __ b(eq, &slow);
1301 __ cmp(r4, Operand(JS_FUNCTION_PROXY_TYPE));
1302 __ b(eq, &slow);
Steve Blocka7e24c12009-10-30 11:49:00 +00001303
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 // Object case: Check key against length in the elements array.
Leon Clarkef7060e22010-06-03 12:02:55 +01001305 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
Iain Merrick75681382010-08-19 15:07:18 +01001306 // Check that the object is in fast mode and writable.
Leon Clarkef7060e22010-06-03 12:02:55 +01001307 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
Leon Clarkef7060e22010-06-03 12:02:55 +01001309 __ cmp(r4, ip);
Steve Block44f0eee2011-05-26 01:26:41 +01001310 __ b(ne, &slow);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001311 // Check array bounds. Both the key and the length of FixedArray are smis.
Leon Clarkef7060e22010-06-03 12:02:55 +01001312 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001313 __ cmp(key, Operand(ip));
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 __ b(lo, &fast);
1315
Leon Clarkef7060e22010-06-03 12:02:55 +01001316 // Slow case, handle jump to runtime.
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 __ bind(&slow);
Leon Clarkef7060e22010-06-03 12:02:55 +01001318 // Entry registers are intact.
1319 // r0: value.
1320 // r1: key.
1321 // r2: receiver.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001322 GenerateRuntimeSetProperty(masm, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001323
1324 // Extra capacity case: Check if there is extra capacity to
1325 // perform the store and update the length. Used for adding one
1326 // element to the array by writing to array[array.length].
Steve Blocka7e24c12009-10-30 11:49:00 +00001327 __ bind(&extra);
Leon Clarkef7060e22010-06-03 12:02:55 +01001328 // Condition code from comparing key and array length is still available.
1329 __ b(ne, &slow); // Only support writing to writing to array[array.length].
1330 // Check for room in the elements backing store.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001331 // Both the key and the length of FixedArray are smis.
Leon Clarkef7060e22010-06-03 12:02:55 +01001332 __ ldr(ip, FieldMemOperand(elements, FixedArray::kLengthOffset));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001333 __ cmp(key, Operand(ip));
Steve Blocka7e24c12009-10-30 11:49:00 +00001334 __ b(hs, &slow);
Leon Clarkef7060e22010-06-03 12:02:55 +01001335 // Calculate key + 1 as smi.
1336 ASSERT_EQ(0, kSmiTag);
1337 __ add(r4, key, Operand(Smi::FromInt(1)));
1338 __ str(r4, FieldMemOperand(receiver, JSArray::kLengthOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001339 __ b(&fast);
1340
Steve Blocka7e24c12009-10-30 11:49:00 +00001341 // Array case: Get the length and the elements array from the JS
Iain Merrick75681382010-08-19 15:07:18 +01001342 // array. Check that the array is in fast mode (and writable); if it
1343 // is the length is always a smi.
Steve Blocka7e24c12009-10-30 11:49:00 +00001344 __ bind(&array);
Leon Clarkef7060e22010-06-03 12:02:55 +01001345 __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1346 __ ldr(r4, FieldMemOperand(elements, HeapObject::kMapOffset));
Steve Blocka7e24c12009-10-30 11:49:00 +00001347 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
Leon Clarkef7060e22010-06-03 12:02:55 +01001348 __ cmp(r4, ip);
Steve Blocka7e24c12009-10-30 11:49:00 +00001349 __ b(ne, &slow);
1350
Leon Clarkef7060e22010-06-03 12:02:55 +01001351 // Check the key against the length in the array.
1352 __ ldr(ip, FieldMemOperand(receiver, JSArray::kLengthOffset));
1353 __ cmp(key, Operand(ip));
Steve Blocka7e24c12009-10-30 11:49:00 +00001354 __ b(hs, &extra);
Leon Clarkef7060e22010-06-03 12:02:55 +01001355 // Fall through to fast case.
Steve Blocka7e24c12009-10-30 11:49:00 +00001356
Steve Blocka7e24c12009-10-30 11:49:00 +00001357 __ bind(&fast);
Leon Clarkef7060e22010-06-03 12:02:55 +01001358 // Fast case, store the value to the elements backing store.
1359 __ add(r5, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1360 __ add(r5, r5, Operand(key, LSL, kPointerSizeLog2 - kSmiTagSize));
1361 __ str(value, MemOperand(r5));
Steve Blocka7e24c12009-10-30 11:49:00 +00001362 // Skip write barrier if the written value is a smi.
Leon Clarkef7060e22010-06-03 12:02:55 +01001363 __ tst(value, Operand(kSmiTagMask));
1364 __ Ret(eq);
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 // Update write barrier for the elements array address.
Leon Clarkef7060e22010-06-03 12:02:55 +01001366 __ sub(r4, r5, Operand(elements));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001367 __ RecordWrite(elements, Operand(r4), r5, r6);
Steve Blocka7e24c12009-10-30 11:49:00 +00001368
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 __ Ret();
1370}
1371
1372
Steve Block1e0659c2011-05-24 12:43:12 +01001373void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001374 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001375 // ----------- S t a t e -------------
1376 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001377 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 // -- r2 : name
1379 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001380 // -----------------------------------
1381
1382 // Get the receiver from the stack and probe the stub cache.
Steve Blocka7e24c12009-10-30 11:49:00 +00001383 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1384 NOT_IN_LOOP,
Steve Block1e0659c2011-05-24 12:43:12 +01001385 MONOMORPHIC,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001386 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001387
1388 Isolate::Current()->stub_cache()->GenerateProbe(
1389 masm, flags, r1, r2, r3, r4, r5);
Steve Blocka7e24c12009-10-30 11:49:00 +00001390
1391 // Cache miss: Jump to runtime.
Leon Clarke4515c472010-02-03 11:58:03 +00001392 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001393}
1394
1395
Leon Clarke4515c472010-02-03 11:58:03 +00001396void StoreIC::GenerateMiss(MacroAssembler* masm) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001397 // ----------- S t a t e -------------
1398 // -- r0 : value
Andrei Popescu402d9372010-02-26 13:31:12 +00001399 // -- r1 : receiver
Steve Blocka7e24c12009-10-30 11:49:00 +00001400 // -- r2 : name
1401 // -- lr : return address
Steve Blocka7e24c12009-10-30 11:49:00 +00001402 // -----------------------------------
1403
Steve Block6ded16b2010-05-10 14:33:55 +01001404 __ Push(r1, r2, r0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001405
1406 // Perform tail call to the entry.
Steve Block44f0eee2011-05-26 01:26:41 +01001407 ExternalReference ref =
1408 ExternalReference(IC_Utility(kStoreIC_Miss), masm->isolate());
Steve Block6ded16b2010-05-10 14:33:55 +01001409 __ TailCallExternalReference(ref, 3, 1);
1410}
1411
1412
1413void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
1414 // ----------- S t a t e -------------
1415 // -- r0 : value
1416 // -- r1 : receiver
1417 // -- r2 : name
1418 // -- lr : return address
1419 // -----------------------------------
1420 //
1421 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1422 // (currently anything except for external and pixel arrays which means
1423 // anything with elements of FixedArray type.), but currently is restricted
1424 // to JSArray.
1425 // Value must be a number, but only smis are accepted as the most common case.
1426
1427 Label miss;
1428
1429 Register receiver = r1;
1430 Register value = r0;
1431 Register scratch = r3;
1432
1433 // Check that the receiver isn't a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001434 __ JumpIfSmi(receiver, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001435
1436 // Check that the object is a JS array.
1437 __ CompareObjectType(receiver, scratch, scratch, JS_ARRAY_TYPE);
1438 __ b(ne, &miss);
1439
1440 // Check that elements are FixedArray.
Iain Merrick75681382010-08-19 15:07:18 +01001441 // We rely on StoreIC_ArrayLength below to deal with all types of
1442 // fast elements (including COW).
Steve Block6ded16b2010-05-10 14:33:55 +01001443 __ ldr(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1444 __ CompareObjectType(scratch, scratch, scratch, FIXED_ARRAY_TYPE);
1445 __ b(ne, &miss);
1446
1447 // Check that value is a smi.
Steve Block1e0659c2011-05-24 12:43:12 +01001448 __ JumpIfNotSmi(value, &miss);
Steve Block6ded16b2010-05-10 14:33:55 +01001449
1450 // Prepare tail call to StoreIC_ArrayLength.
1451 __ Push(receiver, value);
1452
Steve Block44f0eee2011-05-26 01:26:41 +01001453 ExternalReference ref =
1454 ExternalReference(IC_Utility(kStoreIC_ArrayLength), masm->isolate());
Steve Block6ded16b2010-05-10 14:33:55 +01001455 __ TailCallExternalReference(ref, 2, 1);
1456
1457 __ bind(&miss);
1458
1459 GenerateMiss(masm);
Steve Blocka7e24c12009-10-30 11:49:00 +00001460}
1461
1462
Steve Block8defd9f2010-07-08 12:39:36 +01001463void StoreIC::GenerateNormal(MacroAssembler* masm) {
1464 // ----------- S t a t e -------------
1465 // -- r0 : value
1466 // -- r1 : receiver
1467 // -- r2 : name
1468 // -- lr : return address
1469 // -----------------------------------
1470 Label miss;
1471
1472 GenerateStringDictionaryReceiverCheck(masm, r1, r3, r4, r5, &miss);
1473
1474 GenerateDictionaryStore(masm, &miss, r3, r2, r0, r4, r5);
Steve Block44f0eee2011-05-26 01:26:41 +01001475 Counters* counters = masm->isolate()->counters();
1476 __ IncrementCounter(counters->store_normal_hit(),
1477 1, r4, r5);
Steve Block8defd9f2010-07-08 12:39:36 +01001478 __ Ret();
1479
1480 __ bind(&miss);
Steve Block44f0eee2011-05-26 01:26:41 +01001481 __ IncrementCounter(counters->store_normal_miss(), 1, r4, r5);
Steve Block8defd9f2010-07-08 12:39:36 +01001482 GenerateMiss(masm);
1483}
1484
1485
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001486void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1487 StrictModeFlag strict_mode) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001488 // ----------- S t a t e -------------
1489 // -- r0 : value
1490 // -- r1 : receiver
1491 // -- r2 : name
1492 // -- lr : return address
1493 // -----------------------------------
1494
1495 __ Push(r1, r2, r0);
1496
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001497 __ mov(r1, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1498 __ mov(r0, Operand(Smi::FromInt(strict_mode)));
1499 __ Push(r1, r0);
1500
Ben Murdochb0fe1622011-05-05 13:52:32 +01001501 // Do tail-call to runtime routine.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001502 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001503}
1504
1505
Steve Blocka7e24c12009-10-30 11:49:00 +00001506#undef __
1507
1508
Ben Murdochb0fe1622011-05-05 13:52:32 +01001509Condition CompareIC::ComputeCondition(Token::Value op) {
1510 switch (op) {
1511 case Token::EQ_STRICT:
1512 case Token::EQ:
1513 return eq;
1514 case Token::LT:
1515 return lt;
1516 case Token::GT:
1517 // Reverse left and right operands to obtain ECMA-262 conversion order.
1518 return lt;
1519 case Token::LTE:
1520 // Reverse left and right operands to obtain ECMA-262 conversion order.
1521 return ge;
1522 case Token::GTE:
1523 return ge;
1524 default:
1525 UNREACHABLE();
Steve Block1e0659c2011-05-24 12:43:12 +01001526 return kNoCondition;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001527 }
1528}
1529
1530
1531void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
1532 HandleScope scope;
1533 Handle<Code> rewritten;
1534 State previous_state = GetState();
1535 State state = TargetState(previous_state, false, x, y);
1536 if (state == GENERIC) {
1537 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, r1, r0);
1538 rewritten = stub.GetCode();
1539 } else {
1540 ICCompareStub stub(op_, state);
1541 rewritten = stub.GetCode();
1542 }
1543 set_target(*rewritten);
1544
1545#ifdef DEBUG
1546 if (FLAG_trace_ic) {
1547 PrintF("[CompareIC (%s->%s)#%s]\n",
1548 GetStateName(previous_state),
1549 GetStateName(state),
1550 Token::Name(op_));
1551 }
1552#endif
Steve Block1e0659c2011-05-24 12:43:12 +01001553
1554 // Activate inlined smi code.
1555 if (previous_state == UNINITIALIZED) {
1556 PatchInlinedSmiCode(address());
1557 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001558}
1559
1560
1561void PatchInlinedSmiCode(Address address) {
Steve Block1e0659c2011-05-24 12:43:12 +01001562 Address cmp_instruction_address =
1563 address + Assembler::kCallTargetAddressOffset;
1564
1565 // If the instruction following the call is not a cmp rx, #yyy, nothing
1566 // was inlined.
1567 Instr instr = Assembler::instr_at(cmp_instruction_address);
1568 if (!Assembler::IsCmpImmediate(instr)) {
1569 return;
1570 }
1571
1572 // The delta to the start of the map check instruction and the
1573 // condition code uses at the patched jump.
1574 int delta = Assembler::GetCmpImmediateRawImmediate(instr);
1575 delta +=
1576 Assembler::GetCmpImmediateRegister(instr).code() * kOff12Mask;
1577 // If the delta is 0 the instruction is cmp r0, #0 which also signals that
1578 // nothing was inlined.
1579 if (delta == 0) {
1580 return;
1581 }
1582
1583#ifdef DEBUG
1584 if (FLAG_trace_ic) {
1585 PrintF("[ patching ic at %p, cmp=%p, delta=%d\n",
1586 address, cmp_instruction_address, delta);
1587 }
1588#endif
1589
1590 Address patch_address =
1591 cmp_instruction_address - delta * Instruction::kInstrSize;
1592 Instr instr_at_patch = Assembler::instr_at(patch_address);
1593 Instr branch_instr =
1594 Assembler::instr_at(patch_address + Instruction::kInstrSize);
1595 ASSERT(Assembler::IsCmpRegister(instr_at_patch));
1596 ASSERT_EQ(Assembler::GetRn(instr_at_patch).code(),
1597 Assembler::GetRm(instr_at_patch).code());
1598 ASSERT(Assembler::IsBranch(branch_instr));
1599 if (Assembler::GetCondition(branch_instr) == eq) {
1600 // This is patching a "jump if not smi" site to be active.
1601 // Changing
1602 // cmp rx, rx
1603 // b eq, <target>
1604 // to
1605 // tst rx, #kSmiTagMask
1606 // b ne, <target>
1607 CodePatcher patcher(patch_address, 2);
1608 Register reg = Assembler::GetRn(instr_at_patch);
1609 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1610 patcher.EmitCondition(ne);
1611 } else {
1612 ASSERT(Assembler::GetCondition(branch_instr) == ne);
1613 // This is patching a "jump if smi" site to be active.
1614 // Changing
1615 // cmp rx, rx
1616 // b ne, <target>
1617 // to
1618 // tst rx, #kSmiTagMask
1619 // b eq, <target>
1620 CodePatcher patcher(patch_address, 2);
1621 Register reg = Assembler::GetRn(instr_at_patch);
1622 patcher.masm()->tst(reg, Operand(kSmiTagMask));
1623 patcher.EmitCondition(eq);
1624 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001625}
1626
1627
Steve Blocka7e24c12009-10-30 11:49:00 +00001628} } // namespace v8::internal
Leon Clarkef7060e22010-06-03 12:02:55 +01001629
1630#endif // V8_TARGET_ARCH_ARM