blob: 02055a4483a7d75e1088a30a37dde0092530a1eb [file] [log] [blame]
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001// Copyright 2012 the V8 project authors. All rights reserved.
ager@chromium.org5c838252010-02-19 08:53:10 +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
29
30#include "v8.h"
31
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000032#if defined(V8_TARGET_ARCH_MIPS)
33
karlklose@chromium.org83a47282011-05-11 11:54:09 +000034#include "codegen.h"
lrn@chromium.org7516f052011-03-30 08:52:27 +000035#include "code-stubs.h"
ager@chromium.org5c838252010-02-19 08:53:10 +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
50
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000051static void GenerateGlobalInstanceTypeCheck(MacroAssembler* masm,
52 Register type,
53 Label* global_object) {
54 // Register usage:
55 // type: holds the receiver instance type on entry.
56 __ Branch(global_object, eq, type, Operand(JS_GLOBAL_OBJECT_TYPE));
57 __ Branch(global_object, eq, type, Operand(JS_BUILTINS_OBJECT_TYPE));
58 __ Branch(global_object, eq, type, Operand(JS_GLOBAL_PROXY_TYPE));
59}
60
61
62// Generated code falls through if the receiver is a regular non-global
63// JS object with slow properties and no interceptors.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +000064static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
65 Register receiver,
66 Register elements,
67 Register scratch0,
68 Register scratch1,
69 Label* miss) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000070 // Register usage:
71 // receiver: holds the receiver on entry and is unchanged.
72 // elements: holds the property dictionary on fall through.
73 // Scratch registers:
74 // scratch0: used to holds the receiver map.
75 // scratch1: used to holds the receiver instance type, receiver bit mask
76 // and elements map.
77
78 // Check that the receiver isn't a smi.
79 __ JumpIfSmi(receiver, miss);
80
81 // Check that the receiver is a valid JS object.
82 __ GetObjectType(receiver, scratch0, scratch1);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000083 __ Branch(miss, lt, scratch1, Operand(FIRST_SPEC_OBJECT_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000084
85 // If this assert fails, we have to check upper bound too.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000086 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000087
88 GenerateGlobalInstanceTypeCheck(masm, scratch1, miss);
89
90 // Check that the global object does not require access checks.
91 __ lbu(scratch1, FieldMemOperand(scratch0, Map::kBitFieldOffset));
92 __ And(scratch1, scratch1, Operand((1 << Map::kIsAccessCheckNeeded) |
93 (1 << Map::kHasNamedInterceptor)));
94 __ Branch(miss, ne, scratch1, Operand(zero_reg));
95
96 __ lw(elements, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
97 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
98 __ LoadRoot(scratch0, Heap::kHashTableMapRootIndex);
99 __ Branch(miss, ne, scratch1, Operand(scratch0));
100}
101
102
103// Helper function used from LoadIC/CallIC GenerateNormal.
104//
105// elements: Property dictionary. It is not clobbered if a jump to the miss
106// label is done.
107// name: Property name. It is not clobbered if a jump to the miss label is
108// done
109// result: Register for the result. It is only updated if a jump to the miss
110// label is not done. Can be the same as elements or name clobbering
111// one of these in the case of not jumping to the miss label.
112// The two scratch registers need to be different from elements, name and
113// result.
114// The generated code assumes that the receiver has slow properties,
115// is not a global object and does not have interceptors.
116// The address returned from GenerateStringDictionaryProbes() in scratch2
117// is used.
118static void GenerateDictionaryLoad(MacroAssembler* masm,
119 Label* miss,
120 Register elements,
121 Register name,
122 Register result,
123 Register scratch1,
124 Register scratch2) {
125 // Main use of the scratch registers.
126 // scratch1: Used as temporary and to hold the capacity of the property
127 // dictionary.
128 // scratch2: Used as temporary.
129 Label done;
130
131 // Probe the dictionary.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000132 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
133 miss,
134 &done,
135 elements,
136 name,
137 scratch1,
138 scratch2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000139
140 // If probing finds an entry check that the value is a normal
141 // property.
142 __ bind(&done); // scratch2 == elements + 4 * index.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000143 const int kElementsStartOffset = NameDictionary::kHeaderSize +
144 NameDictionary::kElementsStartIndex * kPointerSize;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
146 __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
147 __ And(at,
148 scratch1,
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000149 Operand(PropertyDetails::TypeField::kMask << kSmiTagSize));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000150 __ Branch(miss, ne, at, Operand(zero_reg));
151
152 // Get the value at the masked, scaled index and return.
153 __ lw(result,
154 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.
169// The address returned from GenerateStringDictionaryProbes() in scratch2
170// is used.
171static void GenerateDictionaryStore(MacroAssembler* masm,
172 Label* miss,
173 Register elements,
174 Register name,
175 Register value,
176 Register scratch1,
177 Register scratch2) {
178 // Main use of the scratch registers.
179 // scratch1: Used as temporary and to hold the capacity of the property
180 // dictionary.
181 // scratch2: Used as temporary.
182 Label done;
183
184 // Probe the dictionary.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000185 NameDictionaryLookupStub::GeneratePositiveLookup(masm,
186 miss,
187 &done,
188 elements,
189 name,
190 scratch1,
191 scratch2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000192
193 // If probing finds an entry in the dictionary check that the value
194 // is a normal property that is not read only.
195 __ bind(&done); // scratch2 == elements + 4 * index.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000196 const int kElementsStartOffset = NameDictionary::kHeaderSize +
197 NameDictionary::kElementsStartIndex * kPointerSize;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000198 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000199 const int kTypeAndReadOnlyMask =
200 (PropertyDetails::TypeField::kMask |
201 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000202 __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
203 __ And(at, scratch1, Operand(kTypeAndReadOnlyMask));
204 __ Branch(miss, ne, at, Operand(zero_reg));
205
206 // Store the value at the masked, scaled index and return.
207 const int kValueOffset = kElementsStartOffset + kPointerSize;
208 __ Addu(scratch2, scratch2, Operand(kValueOffset - kHeapObjectTag));
209 __ sw(value, MemOperand(scratch2));
210
211 // Update the write barrier. Make sure not to clobber the value.
212 __ mov(scratch1, value);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000213 __ RecordWrite(
214 elements, scratch2, scratch1, kRAHasNotBeenSaved, kDontSaveFPRegs);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000215}
216
217
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000218// Checks the receiver for special cases (value type, slow case bits).
219// Falls through for regular JS object.
220static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
221 Register receiver,
222 Register map,
223 Register scratch,
224 int interceptor_bit,
225 Label* slow) {
226 // Check that the object isn't a smi.
227 __ JumpIfSmi(receiver, slow);
228 // Get the map of the receiver.
229 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
230 // Check bit field.
231 __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
232 __ And(at, scratch, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
233 __ Branch(slow, ne, at, Operand(zero_reg));
234 // Check that the object is some kind of JS object EXCEPT JS Value type.
235 // In the case that the object is a value-wrapper object,
236 // we enter the runtime system to make sure that indexing into string
237 // objects work as intended.
238 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
239 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
240 __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
241}
242
243
244// Loads an indexed element from a fast case array.
245// If not_fast_array is NULL, doesn't perform the elements map check.
246static void GenerateFastArrayLoad(MacroAssembler* masm,
247 Register receiver,
248 Register key,
249 Register elements,
250 Register scratch1,
251 Register scratch2,
252 Register result,
253 Label* not_fast_array,
254 Label* out_of_range) {
255 // Register use:
256 //
257 // receiver - holds the receiver on entry.
258 // Unchanged unless 'result' is the same register.
259 //
260 // key - holds the smi key on entry.
261 // Unchanged unless 'result' is the same register.
262 //
263 // elements - holds the elements of the receiver on exit.
264 //
265 // result - holds the result on exit if the load succeeded.
266 // Allowed to be the the same as 'receiver' or 'key'.
267 // Unchanged on bailout so 'receiver' and 'key' can be safely
268 // used by further computation.
269 //
270 // Scratch registers:
271 //
272 // scratch1 - used to hold elements map and elements length.
273 // Holds the elements map if not_fast_array branch is taken.
274 //
275 // scratch2 - used to hold the loaded value.
276
277 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
278 if (not_fast_array != NULL) {
279 // Check that the object is in fast mode (not dictionary).
280 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
281 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
282 __ Branch(not_fast_array, ne, scratch1, Operand(at));
283 } else {
284 __ AssertFastElements(elements);
285 }
286
287 // Check that the key (index) is within bounds.
288 __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
289 __ Branch(out_of_range, hs, key, Operand(scratch1));
290
291 // Fast case: Do the load.
292 __ Addu(scratch1, elements,
293 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
294 // The key is a smi.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000295 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000296 __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
297 __ addu(at, at, scratch1);
298 __ lw(scratch2, MemOperand(at));
299
300 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
301 // In case the loaded value is the_hole we have to consult GetProperty
302 // to ensure the prototype chain is searched.
303 __ Branch(out_of_range, eq, scratch2, Operand(at));
304 __ mov(result, scratch2);
305}
306
307
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000308// Checks whether a key is an array index string or a unique name.
309// Falls through if a key is a unique name.
310static void GenerateKeyNameCheck(MacroAssembler* masm,
311 Register key,
312 Register map,
313 Register hash,
314 Label* index_string,
315 Label* not_unique) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000316 // The key is not a smi.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000317 Label unique;
318 // Is it a name?
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000319 __ GetObjectType(key, map, hash);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000320 __ Branch(not_unique, hi, hash, Operand(LAST_UNIQUE_NAME_TYPE));
321 STATIC_ASSERT(LAST_UNIQUE_NAME_TYPE == FIRST_NONSTRING_TYPE);
322 __ Branch(&unique, eq, hash, Operand(LAST_UNIQUE_NAME_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000323
324 // Is the string an array index, with cached numeric value?
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000325 __ lw(hash, FieldMemOperand(key, Name::kHashFieldOffset));
326 __ And(at, hash, Operand(Name::kContainsCachedArrayIndexMask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000327 __ Branch(index_string, eq, at, Operand(zero_reg));
328
ulan@chromium.org750145a2013-03-07 15:14:13 +0000329 // Is the string internalized?
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000330 // map: key map
331 __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
ulan@chromium.org750145a2013-03-07 15:14:13 +0000332 STATIC_ASSERT(kInternalizedTag != 0);
333 __ And(at, hash, Operand(kIsInternalizedMask));
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000334 __ Branch(not_unique, eq, at, Operand(zero_reg));
335
336 __ bind(&unique);
ager@chromium.org5c838252010-02-19 08:53:10 +0000337}
338
339
340// Defined in ic.cc.
341Object* CallIC_Miss(Arguments args);
342
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000343// The generated code does not accept smi keys.
344// The generated code falls through if both probes miss.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000345void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
346 int argc,
347 Code::Kind kind,
348 Code::ExtraICState extra_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000349 // ----------- S t a t e -------------
350 // -- a1 : receiver
351 // -- a2 : name
352 // -----------------------------------
353 Label number, non_number, non_string, boolean, probe, miss;
354
355 // Probe the stub cache.
356 Code::Flags flags = Code::ComputeFlags(kind,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000357 MONOMORPHIC,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000358 extra_state,
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000359 Code::NORMAL,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000360 argc);
361 Isolate::Current()->stub_cache()->GenerateProbe(
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000362 masm, flags, a1, a2, a3, t0, t1, t2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000363
364 // If the stub cache probing failed, the receiver might be a value.
365 // For value objects, we use the map of the prototype objects for
366 // the corresponding JSValue for the cache and that is what we need
367 // to probe.
368 //
369 // Check for number.
370 __ JumpIfSmi(a1, &number, t1);
371 __ GetObjectType(a1, a3, a3);
372 __ Branch(&non_number, ne, a3, Operand(HEAP_NUMBER_TYPE));
373 __ bind(&number);
374 StubCompiler::GenerateLoadGlobalFunctionPrototype(
375 masm, Context::NUMBER_FUNCTION_INDEX, a1);
376 __ Branch(&probe);
377
378 // Check for string.
379 __ bind(&non_number);
380 __ Branch(&non_string, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
381 StubCompiler::GenerateLoadGlobalFunctionPrototype(
382 masm, Context::STRING_FUNCTION_INDEX, a1);
383 __ Branch(&probe);
384
385 // Check for boolean.
386 __ bind(&non_string);
387 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
388 __ Branch(&boolean, eq, a1, Operand(t0));
389 __ LoadRoot(t1, Heap::kFalseValueRootIndex);
390 __ Branch(&miss, ne, a1, Operand(t1));
391 __ bind(&boolean);
392 StubCompiler::GenerateLoadGlobalFunctionPrototype(
393 masm, Context::BOOLEAN_FUNCTION_INDEX, a1);
394
395 // Probe the stub cache for the value object.
396 __ bind(&probe);
397 Isolate::Current()->stub_cache()->GenerateProbe(
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000398 masm, flags, a1, a2, a3, t0, t1, t2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000399
400 __ bind(&miss);
401}
402
403
404static void GenerateFunctionTailCall(MacroAssembler* masm,
405 int argc,
406 Label* miss,
407 Register scratch) {
408 // a1: function
409
410 // Check that the value isn't a smi.
411 __ JumpIfSmi(a1, miss);
412
413 // Check that the value is a JSFunction.
414 __ GetObjectType(a1, scratch, scratch);
415 __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
416
417 // Invoke the function.
418 ParameterCount actual(argc);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000419 __ InvokeFunction(a1, actual, JUMP_FUNCTION,
420 NullCallWrapper(), CALL_AS_METHOD);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000421}
422
423
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000424void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000425 // ----------- S t a t e -------------
426 // -- a2 : name
427 // -- ra : return address
428 // -----------------------------------
429 Label miss;
430
431 // Get the receiver of the function from the stack into a1.
432 __ lw(a1, MemOperand(sp, argc * kPointerSize));
433
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000434 GenerateNameDictionaryReceiverCheck(masm, a1, a0, a3, t0, &miss);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000435
436 // a0: elements
437 // Search the dictionary - put result in register a1.
438 GenerateDictionaryLoad(masm, &miss, a0, a2, a1, a3, t0);
439
440 GenerateFunctionTailCall(masm, argc, &miss, t0);
441
442 // Cache miss: Jump to runtime.
443 __ bind(&miss);
444}
445
446
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000447void CallICBase::GenerateMiss(MacroAssembler* masm,
448 int argc,
449 IC::UtilityId id,
450 Code::ExtraICState extra_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000451 // ----------- S t a t e -------------
452 // -- a2 : name
453 // -- ra : return address
454 // -----------------------------------
455 Isolate* isolate = masm->isolate();
456
457 if (id == IC::kCallIC_Miss) {
458 __ IncrementCounter(isolate->counters()->call_miss(), 1, a3, t0);
459 } else {
460 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, a3, t0);
461 }
462
463 // Get the receiver of the function from the stack.
464 __ lw(a3, MemOperand(sp, argc*kPointerSize));
465
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000466 {
467 FrameScope scope(masm, StackFrame::INTERNAL);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000468
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000469 // Push the receiver and the name of the function.
470 __ Push(a3, a2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000471
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000472 // Call the entry.
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000473 __ PrepareCEntryArgs(2);
474 __ PrepareCEntryFunction(ExternalReference(IC_Utility(id), isolate));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000475
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 CEntryStub stub(1);
477 __ CallStub(&stub);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000478
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000479 // Move result to a1 and leave the internal frame.
480 __ mov(a1, v0);
481 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000482
483 // Check if the receiver is a global object of some sort.
484 // This can happen only for regular CallIC but not KeyedCallIC.
485 if (id == IC::kCallIC_Miss) {
486 Label invoke, global;
487 __ lw(a2, MemOperand(sp, argc * kPointerSize));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000488 __ JumpIfSmi(a2, &invoke);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000489 __ GetObjectType(a2, a3, a3);
490 __ Branch(&global, eq, a3, Operand(JS_GLOBAL_OBJECT_TYPE));
491 __ Branch(&invoke, ne, a3, Operand(JS_BUILTINS_OBJECT_TYPE));
492
493 // Patch the receiver on the stack.
494 __ bind(&global);
495 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
496 __ sw(a2, MemOperand(sp, argc * kPointerSize));
497 __ bind(&invoke);
498 }
499 // Invoke the function.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000500 CallKind call_kind = CallICBase::Contextual::decode(extra_state)
danno@chromium.org40cb8782011-05-25 07:58:50 +0000501 ? CALL_AS_FUNCTION
502 : CALL_AS_METHOD;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000503 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000504 __ InvokeFunction(a1,
505 actual,
506 JUMP_FUNCTION,
507 NullCallWrapper(),
508 call_kind);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000509}
510
lrn@chromium.org7516f052011-03-30 08:52:27 +0000511
danno@chromium.org40cb8782011-05-25 07:58:50 +0000512void CallIC::GenerateMegamorphic(MacroAssembler* masm,
513 int argc,
514 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000515 // ----------- S t a t e -------------
516 // -- a2 : name
517 // -- ra : return address
518 // -----------------------------------
519
520 // Get the receiver of the function from the stack into a1.
521 __ lw(a1, MemOperand(sp, argc * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000522 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
523 GenerateMiss(masm, argc, extra_ic_state);
ager@chromium.org5c838252010-02-19 08:53:10 +0000524}
525
526
lrn@chromium.org7516f052011-03-30 08:52:27 +0000527void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000528 // ----------- S t a t e -------------
529 // -- a2 : name
530 // -- ra : return address
531 // -----------------------------------
532
533 // Get the receiver of the function from the stack into a1.
534 __ lw(a1, MemOperand(sp, argc * kPointerSize));
535
536 Label do_call, slow_call, slow_load, slow_reload_receiver;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000537 Label check_number_dictionary, check_name, lookup_monomorphic_cache;
538 Label index_smi, index_name;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000539
540 // Check that the key is a smi.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000541 __ JumpIfNotSmi(a2, &check_name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000542 __ bind(&index_smi);
543 // Now the key is known to be a smi. This place is also jumped to from below
544 // where a numeric string is converted to a smi.
545
546 GenerateKeyedLoadReceiverCheck(
547 masm, a1, a0, a3, Map::kHasIndexedInterceptor, &slow_call);
548
549 GenerateFastArrayLoad(
550 masm, a1, a2, t0, a3, a0, a1, &check_number_dictionary, &slow_load);
551 Counters* counters = masm->isolate()->counters();
552 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, a0, a3);
553
554 __ bind(&do_call);
555 // receiver in a1 is not used after this point.
556 // a2: key
557 // a1: function
558
559 GenerateFunctionTailCall(masm, argc, &slow_call, a0);
560
561 __ bind(&check_number_dictionary);
562 // a2: key
563 // a3: elements map
564 // t0: elements pointer
565 // Check whether the elements is a number dictionary.
566 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
567 __ Branch(&slow_load, ne, a3, Operand(at));
568 __ sra(a0, a2, kSmiTagSize);
569 // a0: untagged index
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000570 __ LoadFromNumberDictionary(&slow_load, t0, a2, a1, a0, a3, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000571 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3);
572 __ jmp(&do_call);
573
574 __ bind(&slow_load);
575 // This branch is taken when calling KeyedCallIC_Miss is neither required
576 // nor beneficial.
577 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000578 {
579 FrameScope scope(masm, StackFrame::INTERNAL);
580 __ push(a2); // Save the key.
581 __ Push(a1, a2); // Pass the receiver and the key.
582 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
583 __ pop(a2); // Restore the key.
584 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000585 __ mov(a1, v0);
586 __ jmp(&do_call);
587
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000588 __ bind(&check_name);
589 GenerateKeyNameCheck(masm, a2, a0, a3, &index_name, &slow_call);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000590
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000591 // The key is known to be a unique name.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000592 // If the receiver is a regular JS object with slow properties then do
593 // a quick inline probe of the receiver's dictionary.
594 // Otherwise do the monomorphic cache probe.
595 GenerateKeyedLoadReceiverCheck(
596 masm, a1, a0, a3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
597
598 __ lw(a0, FieldMemOperand(a1, JSObject::kPropertiesOffset));
599 __ lw(a3, FieldMemOperand(a0, HeapObject::kMapOffset));
600 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
601 __ Branch(&lookup_monomorphic_cache, ne, a3, Operand(at));
602
603 GenerateDictionaryLoad(masm, &slow_load, a0, a2, a1, a3, t0);
604 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, a0, a3);
605 __ jmp(&do_call);
606
607 __ bind(&lookup_monomorphic_cache);
608 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000609 GenerateMonomorphicCacheProbe(masm,
610 argc,
611 Code::KEYED_CALL_IC,
612 Code::kNoExtraICState);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000613 // Fall through on miss.
614
615 __ bind(&slow_call);
616 // This branch is taken if:
617 // - the receiver requires boxing or access check,
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000618 // - the key is neither smi nor a unique name,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000619 // - the value loaded is not a function,
620 // - there is hope that the runtime will create a monomorphic call stub,
621 // that will get fetched next time.
622 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, a0, a3);
623 GenerateMiss(masm, argc);
624
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000625 __ bind(&index_name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000626 __ IndexFromHash(a3, a2);
627 // Now jump to the place where smi keys are handled.
628 __ jmp(&index_smi);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000629}
630
631
632void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000633 // ----------- S t a t e -------------
634 // -- a2 : name
635 // -- ra : return address
636 // -----------------------------------
637
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000638 // Check if the name is really a name.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000639 Label miss;
640 __ JumpIfSmi(a2, &miss);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000641 __ IsObjectNameType(a2, a0, &miss);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000642
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000643 CallICBase::GenerateNormal(masm, argc);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000644 __ bind(&miss);
645 GenerateMiss(masm, argc);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000646}
647
648
ager@chromium.org5c838252010-02-19 08:53:10 +0000649// Defined in ic.cc.
650Object* LoadIC_Miss(Arguments args);
651
652void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000653 // ----------- S t a t e -------------
654 // -- a2 : name
655 // -- ra : return address
656 // -- a0 : receiver
657 // -- sp[0] : receiver
658 // -----------------------------------
659
660 // Probe the stub cache.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000661 Code::Flags flags = Code::ComputeFlags(
662 Code::STUB, MONOMORPHIC, Code::kNoExtraICState,
663 Code::NORMAL, Code::LOAD_IC);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664 Isolate::Current()->stub_cache()->GenerateProbe(
fschneider@chromium.org35814e52012-03-01 15:43:35 +0000665 masm, flags, a0, a2, a3, t0, t1, t2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000666
667 // Cache miss: Jump to runtime.
668 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +0000669}
670
671
672void LoadIC::GenerateNormal(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000673 // ----------- S t a t e -------------
674 // -- a2 : name
675 // -- lr : return address
676 // -- a0 : receiver
677 // -- sp[0] : receiver
678 // -----------------------------------
679 Label miss;
680
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000681 GenerateNameDictionaryReceiverCheck(masm, a0, a1, a3, t0, &miss);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000682
683 // a1: elements
684 GenerateDictionaryLoad(masm, &miss, a1, a2, v0, a3, t0);
685 __ Ret();
686
687 // Cache miss: Jump to runtime.
688 __ bind(&miss);
689 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +0000690}
691
692
693void LoadIC::GenerateMiss(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000694 // ----------- S t a t e -------------
695 // -- a2 : name
696 // -- ra : return address
697 // -- a0 : receiver
698 // -- sp[0] : receiver
699 // -----------------------------------
700 Isolate* isolate = masm->isolate();
701
702 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
703
704 __ mov(a3, a0);
705 __ Push(a3, a2);
706
707 // Perform tail call to the entry.
708 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
709 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000710}
711
712
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000713static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
714 Register object,
715 Register key,
716 Register scratch1,
717 Register scratch2,
718 Register scratch3,
719 Label* unmapped_case,
720 Label* slow_case) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000721 // Check that the receiver is a JSObject. Because of the map check
722 // later, we do not need to check for interceptors or whether it
723 // requires access checks.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000724 __ JumpIfSmi(object, slow_case);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000725 // Check that the object is some kind of JSObject.
726 __ GetObjectType(object, scratch1, scratch2);
727 __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000728
729 // Check that the key is a positive smi.
danno@chromium.orgb10deab2012-05-07 14:28:47 +0000730 __ And(scratch1, key, Operand(0x80000001));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000731 __ Branch(slow_case, ne, scratch1, Operand(zero_reg));
732
733 // Load the elements into scratch1 and check its map.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000734 __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000735 __ CheckMap(scratch1,
736 scratch2,
737 Heap::kNonStrictArgumentsElementsMapRootIndex,
738 slow_case,
739 DONT_DO_SMI_CHECK);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000740 // Check if element is in the range of mapped arguments. If not, jump
741 // to the unmapped lookup with the parameter map in scratch1.
742 __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
743 __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2)));
744 __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2));
745
746 // Load element index and check whether it is the hole.
747 const int kOffset =
748 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
749
750 __ li(scratch3, Operand(kPointerSize >> 1));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000751 __ Mul(scratch3, key, scratch3);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000752 __ Addu(scratch3, scratch3, Operand(kOffset));
753
754 __ Addu(scratch2, scratch1, scratch3);
755 __ lw(scratch2, MemOperand(scratch2));
756 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
757 __ Branch(unmapped_case, eq, scratch2, Operand(scratch3));
758
759 // Load value from context and return it. We can reuse scratch1 because
760 // we do not jump to the unmapped lookup (which requires the parameter
761 // map in scratch1).
762 __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
763 __ li(scratch3, Operand(kPointerSize >> 1));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000764 __ Mul(scratch3, scratch2, scratch3);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000765 __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
766 __ Addu(scratch2, scratch1, scratch3);
767 return MemOperand(scratch2);
768}
769
770
771static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
772 Register key,
773 Register parameter_map,
774 Register scratch,
775 Label* slow_case) {
776 // Element is in arguments backing store, which is referenced by the
777 // second element of the parameter_map. The parameter_map register
778 // must be loaded with the parameter map of the arguments object and is
779 // overwritten.
780 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
781 Register backing_store = parameter_map;
782 __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000783 __ CheckMap(backing_store,
784 scratch,
785 Heap::kFixedArrayMapRootIndex,
786 slow_case,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000787 DONT_DO_SMI_CHECK);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000788 __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
789 __ Branch(slow_case, Ugreater_equal, key, Operand(scratch));
790 __ li(scratch, Operand(kPointerSize >> 1));
mstarzinger@chromium.org3233d2f2012-03-14 11:16:03 +0000791 __ Mul(scratch, key, scratch);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000792 __ Addu(scratch,
793 scratch,
794 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
795 __ Addu(scratch, backing_store, scratch);
796 return MemOperand(scratch);
797}
798
799
800void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
801 // ---------- S t a t e --------------
802 // -- lr : return address
803 // -- a0 : key
804 // -- a1 : receiver
805 // -----------------------------------
806 Label slow, notin;
807 MemOperand mapped_location =
808 GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, &notin, &slow);
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000809 __ Ret(USE_DELAY_SLOT);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000810 __ lw(v0, mapped_location);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000811 __ bind(&notin);
812 // The unmapped lookup expects that the parameter map is in a2.
813 MemOperand unmapped_location =
814 GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow);
815 __ lw(a2, unmapped_location);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000816 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000817 __ Branch(&slow, eq, a2, Operand(a3));
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000818 __ Ret(USE_DELAY_SLOT);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000819 __ mov(v0, a2);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000820 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000821 GenerateMiss(masm, MISS);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000822}
823
824
825void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
826 // ---------- S t a t e --------------
827 // -- a0 : value
828 // -- a1 : key
829 // -- a2 : receiver
830 // -- lr : return address
831 // -----------------------------------
832 Label slow, notin;
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000833 // Store address is returned in register (of MemOperand) mapped_location.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000834 MemOperand mapped_location =
835 GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, &notin, &slow);
836 __ sw(a0, mapped_location);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000837 __ mov(t5, a0);
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000838 ASSERT_EQ(mapped_location.offset(), 0);
839 __ RecordWrite(a3, mapped_location.rm(), t5,
840 kRAHasNotBeenSaved, kDontSaveFPRegs);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000841 __ Ret(USE_DELAY_SLOT);
842 __ mov(v0, a0); // (In delay slot) return the value stored in v0.
843 __ bind(&notin);
844 // The unmapped lookup expects that the parameter map is in a3.
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000845 // Store address is returned in register (of MemOperand) unmapped_location.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000846 MemOperand unmapped_location =
847 GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
848 __ sw(a0, unmapped_location);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +0000849 __ mov(t5, a0);
danno@chromium.orgbf0c8202011-12-27 10:09:42 +0000850 ASSERT_EQ(unmapped_location.offset(), 0);
851 __ RecordWrite(a3, unmapped_location.rm(), t5,
852 kRAHasNotBeenSaved, kDontSaveFPRegs);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000853 __ Ret(USE_DELAY_SLOT);
854 __ mov(v0, a0); // (In delay slot) return the value stored in v0.
855 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000856 GenerateMiss(masm, MISS);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000857}
858
859
860void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
861 int argc) {
862 // ----------- S t a t e -------------
863 // -- a2 : name
864 // -- lr : return address
865 // -----------------------------------
866 Label slow, notin;
867 // Load receiver.
868 __ lw(a1, MemOperand(sp, argc * kPointerSize));
869 MemOperand mapped_location =
870 GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, &notin, &slow);
871 __ lw(a1, mapped_location);
872 GenerateFunctionTailCall(masm, argc, &slow, a3);
873 __ bind(&notin);
874 // The unmapped lookup expects that the parameter map is in a3.
875 MemOperand unmapped_location =
876 GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow);
877 __ lw(a1, unmapped_location);
878 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
879 __ Branch(&slow, eq, a1, Operand(a3));
880 GenerateFunctionTailCall(masm, argc, &slow, a3);
881 __ bind(&slow);
882 GenerateMiss(masm, argc);
883}
884
885
886Object* KeyedLoadIC_Miss(Arguments args);
887
888
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000889void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000890 // ---------- S t a t e --------------
891 // -- ra : return address
892 // -- a0 : key
893 // -- a1 : receiver
894 // -----------------------------------
895 Isolate* isolate = masm->isolate();
896
897 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
898
899 __ Push(a1, a0);
900
danno@chromium.org40cb8782011-05-25 07:58:50 +0000901 // Perform tail call to the entry.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000902 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
danno@chromium.org40cb8782011-05-25 07:58:50 +0000903 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
904 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
905
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000906 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000907}
908
909
lrn@chromium.org7516f052011-03-30 08:52:27 +0000910void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000911 // ---------- S t a t e --------------
912 // -- ra : return address
913 // -- a0 : key
914 // -- a1 : receiver
915 // -----------------------------------
916
917 __ Push(a1, a0);
918
919 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000920}
921
922
ager@chromium.org5c838252010-02-19 08:53:10 +0000923void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000924 // ---------- S t a t e --------------
925 // -- ra : return address
926 // -- a0 : key
927 // -- a1 : receiver
928 // -----------------------------------
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000929 Label slow, check_name, index_smi, index_name, property_array_property;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000930 Label probe_dictionary, check_number_dictionary;
931
932 Register key = a0;
933 Register receiver = a1;
934
935 Isolate* isolate = masm->isolate();
936
937 // Check that the key is a smi.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000938 __ JumpIfNotSmi(key, &check_name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000939 __ bind(&index_smi);
940 // Now the key is known to be a smi. This place is also jumped to from below
941 // where a numeric string is converted to a smi.
942
943 GenerateKeyedLoadReceiverCheck(
944 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
945
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000946 // Check the receiver's map to see if it has fast elements.
947 __ CheckFastElements(a2, a3, &check_number_dictionary);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000948
949 GenerateFastArrayLoad(
950 masm, receiver, key, t0, a3, a2, v0, NULL, &slow);
951
952 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3);
953 __ Ret();
954
955 __ bind(&check_number_dictionary);
956 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
957 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset));
958
959 // Check whether the elements is a number dictionary.
960 // a0: key
961 // a3: elements map
962 // t0: elements
963 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
964 __ Branch(&slow, ne, a3, Operand(at));
965 __ sra(a2, a0, kSmiTagSize);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000966 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000967 __ Ret();
968
969 // Slow case, key and receiver still in a0 and a1.
970 __ bind(&slow);
971 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
972 1,
973 a2,
974 a3);
975 GenerateRuntimeGetProperty(masm);
976
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000977 __ bind(&check_name);
978 GenerateKeyNameCheck(masm, key, a2, a3, &index_name, &slow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000979
980 GenerateKeyedLoadReceiverCheck(
981 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
982
983
984 // If the receiver is a fast-case object, check the keyed lookup
985 // cache. Otherwise probe the dictionary.
986 __ lw(a3, FieldMemOperand(a1, JSObject::kPropertiesOffset));
987 __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
988 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
989 __ Branch(&probe_dictionary, eq, t0, Operand(at));
990
991 // Load the map of the receiver, compute the keyed lookup cache hash
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000992 // based on 32 bits of the map pointer and the name hash.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000993 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
994 __ sra(a3, a2, KeyedLookupCache::kMapHashShift);
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000995 __ lw(t0, FieldMemOperand(a0, Name::kHashFieldOffset));
996 __ sra(at, t0, Name::kHashShift);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000997 __ xor_(a3, a3, at);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000998 int mask = KeyedLookupCache::kCapacityMask & KeyedLookupCache::kHashMask;
999 __ And(a3, a3, Operand(mask));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001000
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001001 // Load the key (consisting of map and unique name) from the cache and
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001002 // check for match.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001003 Label load_in_object_property;
1004 static const int kEntriesPerBucket = KeyedLookupCache::kEntriesPerBucket;
1005 Label hit_on_nth_entry[kEntriesPerBucket];
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001006 ExternalReference cache_keys =
1007 ExternalReference::keyed_lookup_cache_keys(isolate);
1008 __ li(t0, Operand(cache_keys));
1009 __ sll(at, a3, kPointerSizeLog2 + 1);
1010 __ addu(t0, t0, at);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001011
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001012 for (int i = 0; i < kEntriesPerBucket - 1; i++) {
1013 Label try_next_entry;
1014 __ lw(t1, MemOperand(t0, kPointerSize * i * 2));
1015 __ Branch(&try_next_entry, ne, a2, Operand(t1));
1016 __ lw(t1, MemOperand(t0, kPointerSize * (i * 2 + 1)));
1017 __ Branch(&hit_on_nth_entry[i], eq, a0, Operand(t1));
1018 __ bind(&try_next_entry);
1019 }
1020
1021 __ lw(t1, MemOperand(t0, kPointerSize * (kEntriesPerBucket - 1) * 2));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001022 __ Branch(&slow, ne, a2, Operand(t1));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001023 __ lw(t1, MemOperand(t0, kPointerSize * ((kEntriesPerBucket - 1) * 2 + 1)));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001024 __ Branch(&slow, ne, a0, Operand(t1));
1025
1026 // Get field offset.
1027 // a0 : key
1028 // a1 : receiver
1029 // a2 : receiver's map
1030 // a3 : lookup cache index
1031 ExternalReference cache_field_offsets =
1032 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001033
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001034 // Hit on nth entry.
1035 for (int i = kEntriesPerBucket - 1; i >= 0; i--) {
1036 __ bind(&hit_on_nth_entry[i]);
1037 __ li(t0, Operand(cache_field_offsets));
1038 __ sll(at, a3, kPointerSizeLog2);
1039 __ addu(at, t0, at);
1040 __ lw(t1, MemOperand(at, kPointerSize * i));
1041 __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
1042 __ Subu(t1, t1, t2);
1043 __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
1044 if (i != 0) {
1045 __ Branch(&load_in_object_property);
1046 }
1047 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001048
1049 // Load in-object property.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001050 __ bind(&load_in_object_property);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001051 __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset));
1052 __ addu(t2, t2, t1); // Index from start of object.
1053 __ Subu(a1, a1, Operand(kHeapObjectTag)); // Remove the heap tag.
1054 __ sll(at, t2, kPointerSizeLog2);
1055 __ addu(at, a1, at);
1056 __ lw(v0, MemOperand(at));
1057 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1058 1,
1059 a2,
1060 a3);
1061 __ Ret();
1062
1063 // Load property array property.
1064 __ bind(&property_array_property);
1065 __ lw(a1, FieldMemOperand(a1, JSObject::kPropertiesOffset));
1066 __ Addu(a1, a1, FixedArray::kHeaderSize - kHeapObjectTag);
1067 __ sll(t0, t1, kPointerSizeLog2);
1068 __ Addu(t0, t0, a1);
1069 __ lw(v0, MemOperand(t0));
1070 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1071 1,
1072 a2,
1073 a3);
1074 __ Ret();
1075
1076
1077 // Do a quick inline probe of the receiver's dictionary, if it
1078 // exists.
1079 __ bind(&probe_dictionary);
1080 // a1: receiver
1081 // a0: key
1082 // a3: elements
1083 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1084 __ lbu(a2, FieldMemOperand(a2, Map::kInstanceTypeOffset));
1085 GenerateGlobalInstanceTypeCheck(masm, a2, &slow);
1086 // Load the property to v0.
1087 GenerateDictionaryLoad(masm, &slow, a3, a0, v0, a2, t0);
1088 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1089 1,
1090 a2,
1091 a3);
1092 __ Ret();
1093
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001094 __ bind(&index_name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001095 __ IndexFromHash(a3, key);
1096 // Now jump to the place where smi keys are handled.
1097 __ Branch(&index_smi);
ager@chromium.org5c838252010-02-19 08:53:10 +00001098}
1099
1100
1101void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001102 // ---------- S t a t e --------------
1103 // -- ra : return address
1104 // -- a0 : key (index)
1105 // -- a1 : receiver
1106 // -----------------------------------
1107 Label miss;
1108
1109 Register receiver = a1;
1110 Register index = a0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001111 Register scratch = a3;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001112 Register result = v0;
1113
1114 StringCharAtGenerator char_at_generator(receiver,
1115 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00001116 scratch,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001117 result,
1118 &miss, // When not a string.
1119 &miss, // When not a number.
1120 &miss, // When index out of range.
1121 STRING_INDEX_IS_ARRAY_INDEX);
1122 char_at_generator.GenerateFast(masm);
1123 __ Ret();
1124
1125 StubRuntimeCallHelper call_helper;
1126 char_at_generator.GenerateSlow(masm, call_helper);
1127
1128 __ bind(&miss);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001129 GenerateMiss(masm, MISS);
ager@chromium.org5c838252010-02-19 08:53:10 +00001130}
1131
1132
lrn@chromium.org7516f052011-03-30 08:52:27 +00001133void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1134 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001135 // ---------- S t a t e --------------
1136 // -- a0 : value
1137 // -- a1 : key
1138 // -- a2 : receiver
1139 // -- ra : return address
1140 // -----------------------------------
1141
1142 // Push receiver, key and value for runtime call.
1143 __ Push(a2, a1, a0);
1144 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1145 __ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1146 __ Push(a1, a0);
1147
1148 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001149}
1150
1151
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001152static void KeyedStoreGenerateGenericHelper(
1153 MacroAssembler* masm,
1154 Label* fast_object,
1155 Label* fast_double,
1156 Label* slow,
1157 KeyedStoreCheckMap check_map,
1158 KeyedStoreIncrementLength increment_length,
1159 Register value,
1160 Register key,
1161 Register receiver,
1162 Register receiver_map,
1163 Register elements_map,
1164 Register elements) {
1165 Label transition_smi_elements;
1166 Label finish_object_store, non_double_value, transition_double_elements;
1167 Label fast_double_without_map_check;
1168
1169 // Fast case: Do the store, could be either Object or double.
1170 __ bind(fast_object);
1171 Register scratch_value = t0;
1172 Register address = t1;
1173 if (check_map == kCheckMap) {
1174 __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
1175 __ Branch(fast_double, ne, elements_map,
1176 Operand(masm->isolate()->factory()->fixed_array_map()));
1177 }
1178 // Smi stores don't require further checks.
1179 Label non_smi_value;
1180 __ JumpIfNotSmi(value, &non_smi_value);
1181
1182 if (increment_length == kIncrementLength) {
1183 // Add 1 to receiver->length.
1184 __ Addu(scratch_value, key, Operand(Smi::FromInt(1)));
1185 __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1186 }
1187 // It's irrelevant whether array is smi-only or not when writing a smi.
1188 __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1189 __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
1190 __ Addu(address, address, scratch_value);
1191 __ sw(value, MemOperand(address));
1192 __ Ret();
1193
1194 __ bind(&non_smi_value);
1195 // Escape to elements kind transition case.
1196 __ CheckFastObjectElements(receiver_map, scratch_value,
1197 &transition_smi_elements);
1198
1199 // Fast elements array, store the value to the elements backing store.
1200 __ bind(&finish_object_store);
1201 if (increment_length == kIncrementLength) {
1202 // Add 1 to receiver->length.
1203 __ Addu(scratch_value, key, Operand(Smi::FromInt(1)));
1204 __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1205 }
1206 __ Addu(address, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1207 __ sll(scratch_value, key, kPointerSizeLog2 - kSmiTagSize);
1208 __ Addu(address, address, scratch_value);
1209 __ sw(value, MemOperand(address));
1210 // Update write barrier for the elements array address.
1211 __ mov(scratch_value, value); // Preserve the value which is returned.
1212 __ RecordWrite(elements,
1213 address,
1214 scratch_value,
1215 kRAHasNotBeenSaved,
1216 kDontSaveFPRegs,
1217 EMIT_REMEMBERED_SET,
1218 OMIT_SMI_CHECK);
1219 __ Ret();
1220
1221 __ bind(fast_double);
1222 if (check_map == kCheckMap) {
1223 // Check for fast double array case. If this fails, call through to the
1224 // runtime.
1225 __ LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
1226 __ Branch(slow, ne, elements_map, Operand(at));
1227 }
1228 __ bind(&fast_double_without_map_check);
1229 __ StoreNumberToDoubleElements(value,
1230 key,
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001231 elements, // Overwritten.
1232 a3, // Scratch regs...
1233 t0,
1234 t1,
1235 t2,
1236 &transition_double_elements);
1237 if (increment_length == kIncrementLength) {
1238 // Add 1 to receiver->length.
1239 __ Addu(scratch_value, key, Operand(Smi::FromInt(1)));
1240 __ sw(scratch_value, FieldMemOperand(receiver, JSArray::kLengthOffset));
1241 }
1242 __ Ret();
1243
1244 __ bind(&transition_smi_elements);
1245 // Transition the array appropriately depending on the value type.
1246 __ lw(t0, FieldMemOperand(value, HeapObject::kMapOffset));
1247 __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
1248 __ Branch(&non_double_value, ne, t0, Operand(at));
1249
1250 // Value is a double. Transition FAST_SMI_ELEMENTS ->
1251 // FAST_DOUBLE_ELEMENTS and complete the store.
1252 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1253 FAST_DOUBLE_ELEMENTS,
1254 receiver_map,
1255 t0,
1256 slow);
1257 ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001258 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1259 FAST_DOUBLE_ELEMENTS);
1260 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, slow);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001261 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1262 __ jmp(&fast_double_without_map_check);
1263
1264 __ bind(&non_double_value);
1265 // Value is not a double, FAST_SMI_ELEMENTS -> FAST_ELEMENTS
1266 __ LoadTransitionedArrayMapConditional(FAST_SMI_ELEMENTS,
1267 FAST_ELEMENTS,
1268 receiver_map,
1269 t0,
1270 slow);
1271 ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001272 mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
1273 ElementsTransitionGenerator::GenerateMapChangeElementsTransition(masm, mode,
1274 slow);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001275 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1276 __ jmp(&finish_object_store);
1277
1278 __ bind(&transition_double_elements);
1279 // Elements are FAST_DOUBLE_ELEMENTS, but value is an Object that's not a
1280 // HeapNumber. Make sure that the receiver is a Array with FAST_ELEMENTS and
1281 // transition array from FAST_DOUBLE_ELEMENTS to FAST_ELEMENTS
1282 __ LoadTransitionedArrayMapConditional(FAST_DOUBLE_ELEMENTS,
1283 FAST_ELEMENTS,
1284 receiver_map,
1285 t0,
1286 slow);
1287 ASSERT(receiver_map.is(a3)); // Transition code expects map in a3
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001288 mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
1289 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, slow);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001290 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1291 __ jmp(&finish_object_store);
1292}
1293
1294
lrn@chromium.org7516f052011-03-30 08:52:27 +00001295void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1296 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001297 // ---------- S t a t e --------------
1298 // -- a0 : value
1299 // -- a1 : key
1300 // -- a2 : receiver
1301 // -- ra : return address
1302 // -----------------------------------
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001303 Label slow, fast_object, fast_object_grow;
1304 Label fast_double, fast_double_grow;
1305 Label array, extra, check_if_double_array;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001306
1307 // Register usage.
1308 Register value = a0;
1309 Register key = a1;
1310 Register receiver = a2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001311 Register receiver_map = a3;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001312 Register elements_map = t2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001313 Register elements = t3; // Elements array of the receiver.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001314 // t0 and t1 are used as general scratch registers.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001315
1316 // Check that the key is a smi.
1317 __ JumpIfNotSmi(key, &slow);
1318 // Check that the object isn't a smi.
1319 __ JumpIfSmi(receiver, &slow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001320 // Get the map of the object.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001321 __ lw(receiver_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001322 // Check that the receiver does not require access checks. We need
1323 // to do this because this generic stub does not perform map checks.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001324 __ lbu(t0, FieldMemOperand(receiver_map, Map::kBitFieldOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001325 __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
1326 __ Branch(&slow, ne, t0, Operand(zero_reg));
1327 // Check if the object is a JS array or not.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001328 __ lbu(t0, FieldMemOperand(receiver_map, Map::kInstanceTypeOffset));
1329 __ Branch(&array, eq, t0, Operand(JS_ARRAY_TYPE));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001330 // Check that the object is some kind of JSObject.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001331 __ Branch(&slow, lt, t0, Operand(FIRST_JS_OBJECT_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001332
1333 // Object case: Check key against length in the elements array.
1334 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001335 // Check array bounds. Both the key and the length of FixedArray are smis.
1336 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001337 __ Branch(&fast_object, lo, key, Operand(t0));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001338
1339 // Slow case, handle jump to runtime.
1340 __ bind(&slow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001341 // Entry registers are intact.
1342 // a0: value.
1343 // a1: key.
1344 // a2: receiver.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001345 GenerateRuntimeSetProperty(masm, strict_mode);
1346
1347 // Extra capacity case: Check if there is extra capacity to
1348 // perform the store and update the length. Used for adding one
1349 // element to the array by writing to array[array.length].
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001350 __ bind(&extra);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001351 // Condition code from comparing key and array length is still available.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001352 // Only support writing to array[array.length].
1353 __ Branch(&slow, ne, key, Operand(t0));
1354 // Check for room in the elements backing store.
1355 // Both the key and the length of FixedArray are smis.
1356 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1357 __ Branch(&slow, hs, key, Operand(t0));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001358 __ lw(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +00001359 __ Branch(
1360 &check_if_double_array, ne, elements_map, Heap::kFixedArrayMapRootIndex);
1361
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001362 __ jmp(&fast_object_grow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001363
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001364 __ bind(&check_if_double_array);
danno@chromium.org88aa0582012-03-23 15:11:57 +00001365 __ Branch(&slow, ne, elements_map, Heap::kFixedDoubleArrayMapRootIndex);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001366 __ jmp(&fast_double_grow);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001367
1368 // Array case: Get the length and the elements array from the JS
1369 // array. Check that the array is in fast mode (and writable); if it
1370 // is the length is always a smi.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001371 __ bind(&array);
1372 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001373
1374 // Check the key against the length in the array.
1375 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1376 __ Branch(&extra, hs, key, Operand(t0));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001377
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001378 KeyedStoreGenerateGenericHelper(masm, &fast_object, &fast_double,
1379 &slow, kCheckMap, kDontIncrementLength,
1380 value, key, receiver, receiver_map,
1381 elements_map, elements);
1382 KeyedStoreGenerateGenericHelper(masm, &fast_object_grow, &fast_double_grow,
1383 &slow, kDontCheckMap, kIncrementLength,
1384 value, key, receiver, receiver_map,
1385 elements_map, elements);
ager@chromium.org5c838252010-02-19 08:53:10 +00001386}
1387
1388
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001389void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001390 // ---------- S t a t e --------------
1391 // -- ra : return address
1392 // -- a0 : key
1393 // -- a1 : receiver
1394 // -----------------------------------
1395 Label slow;
1396
1397 // Check that the receiver isn't a smi.
1398 __ JumpIfSmi(a1, &slow);
1399
1400 // Check that the key is an array index, that is Uint32.
1401 __ And(t0, a0, Operand(kSmiTagMask | kSmiSignMask));
1402 __ Branch(&slow, ne, t0, Operand(zero_reg));
1403
1404 // Get the map of the receiver.
1405 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1406
1407 // Check that it has indexed interceptor and access checks
1408 // are not enabled for this object.
1409 __ lbu(a3, FieldMemOperand(a2, Map::kBitFieldOffset));
1410 __ And(a3, a3, Operand(kSlowCaseBitFieldMask));
1411 __ Branch(&slow, ne, a3, Operand(1 << Map::kHasIndexedInterceptor));
1412 // Everything is fine, call runtime.
1413 __ Push(a1, a0); // Receiver, key.
1414
1415 // Perform tail call to the entry.
1416 __ TailCallExternalReference(ExternalReference(
1417 IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1);
1418
1419 __ bind(&slow);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001420 GenerateMiss(masm, MISS);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001421}
1422
1423
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001424void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, ICMissMode miss_mode) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00001425 // ---------- S t a t e --------------
1426 // -- a0 : value
1427 // -- a1 : key
1428 // -- a2 : receiver
1429 // -- ra : return address
1430 // -----------------------------------
1431
1432 // Push receiver, key and value for runtime call.
1433 __ Push(a2, a1, a0);
1434
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001435 ExternalReference ref = miss_mode == MISS_FORCE_GENERIC
danno@chromium.org40cb8782011-05-25 07:58:50 +00001436 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1437 masm->isolate())
1438 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1439 __ TailCallExternalReference(ref, 3, 1);
1440}
1441
1442
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001443void StoreIC::GenerateSlow(MacroAssembler* masm) {
1444 // ---------- S t a t e --------------
1445 // -- a0 : value
1446 // -- a2 : key
1447 // -- a1 : receiver
1448 // -- ra : return address
1449 // -----------------------------------
1450
1451 // Push receiver, key and value for runtime call.
1452 __ Push(a1, a2, a0);
1453
1454 // The slow case calls into the runtime to complete the store without causing
1455 // an IC miss that would otherwise cause a transition to the generic stub.
1456 ExternalReference ref =
1457 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1458 __ TailCallExternalReference(ref, 3, 1);
1459}
1460
1461
danno@chromium.org40cb8782011-05-25 07:58:50 +00001462void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001463 // ---------- S t a t e --------------
1464 // -- a0 : value
1465 // -- a1 : key
1466 // -- a2 : receiver
1467 // -- ra : return address
1468 // -----------------------------------
1469
1470 // Push receiver, key and value for runtime call.
1471 // We can't use MultiPush as the order of the registers is important.
1472 __ Push(a2, a1, a0);
1473
danno@chromium.org40cb8782011-05-25 07:58:50 +00001474 // The slow case calls into the runtime to complete the store without causing
1475 // an IC miss that would otherwise cause a transition to the generic stub.
1476 ExternalReference ref =
1477 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1478
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001479 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001480}
1481
1482
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001483void KeyedStoreIC::GenerateTransitionElementsSmiToDouble(MacroAssembler* masm) {
1484 // ---------- S t a t e --------------
1485 // -- a2 : receiver
1486 // -- a3 : target map
1487 // -- ra : return address
1488 // -----------------------------------
1489 // Must return the modified receiver in v0.
1490 if (!FLAG_trace_elements_transitions) {
1491 Label fail;
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001492 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_SMI_ELEMENTS,
1493 FAST_DOUBLE_ELEMENTS);
1494 ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001495 __ Ret(USE_DELAY_SLOT);
1496 __ mov(v0, a2);
1497 __ bind(&fail);
1498 }
1499
1500 __ push(a2);
1501 __ TailCallRuntime(Runtime::kTransitionElementsSmiToDouble, 1, 1);
1502}
1503
1504
1505void KeyedStoreIC::GenerateTransitionElementsDoubleToObject(
1506 MacroAssembler* masm) {
1507 // ---------- S t a t e --------------
1508 // -- a2 : receiver
1509 // -- a3 : target map
1510 // -- ra : return address
1511 // -----------------------------------
1512 // Must return the modified receiver in v0.
1513 if (!FLAG_trace_elements_transitions) {
1514 Label fail;
yangguo@chromium.org28381b42013-01-21 14:39:38 +00001515 AllocationSiteMode mode = AllocationSiteInfo::GetMode(FAST_DOUBLE_ELEMENTS,
1516 FAST_ELEMENTS);
1517 ElementsTransitionGenerator::GenerateDoubleToObject(masm, mode, &fail);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001518 __ Ret(USE_DELAY_SLOT);
1519 __ mov(v0, a2);
1520 __ bind(&fail);
1521 }
1522
1523 __ push(a2);
1524 __ TailCallRuntime(Runtime::kTransitionElementsDoubleToObject, 1, 1);
1525}
1526
1527
lrn@chromium.org7516f052011-03-30 08:52:27 +00001528void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1529 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001530 // ----------- S t a t e -------------
1531 // -- a0 : value
1532 // -- a1 : receiver
1533 // -- a2 : name
1534 // -- ra : return address
1535 // -----------------------------------
1536
1537 // Get the receiver from the stack and probe the stub cache.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001538 Code::Flags flags =
1539 Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001540 Isolate::Current()->stub_cache()->GenerateProbe(
fschneider@chromium.org35814e52012-03-01 15:43:35 +00001541 masm, flags, a1, a2, a3, t0, t1, t2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001542
1543 // Cache miss: Jump to runtime.
1544 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +00001545}
1546
1547
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001548void StoreIC::GenerateMiss(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001549 // ----------- S t a t e -------------
1550 // -- a0 : value
1551 // -- a1 : receiver
1552 // -- a2 : name
1553 // -- ra : return address
1554 // -----------------------------------
1555
1556 __ Push(a1, a2, a0);
1557 // Perform tail call to the entry.
1558 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
1559 masm->isolate());
1560 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001561}
1562
1563
lrn@chromium.org7516f052011-03-30 08:52:27 +00001564void StoreIC::GenerateNormal(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001565 // ----------- S t a t e -------------
1566 // -- a0 : value
1567 // -- a1 : receiver
1568 // -- a2 : name
1569 // -- ra : return address
1570 // -----------------------------------
1571 Label miss;
1572
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001573 GenerateNameDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001574
1575 GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1);
1576 Counters* counters = masm->isolate()->counters();
1577 __ IncrementCounter(counters->store_normal_hit(), 1, t0, t1);
1578 __ Ret();
1579
1580 __ bind(&miss);
1581 __ IncrementCounter(counters->store_normal_miss(), 1, t0, t1);
1582 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001583}
1584
1585
1586void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1587 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001588 // ----------- S t a t e -------------
1589 // -- a0 : value
1590 // -- a1 : receiver
1591 // -- a2 : name
1592 // -- ra : return address
1593 // -----------------------------------
1594
1595 __ Push(a1, a2, a0);
1596
1597 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1598 __ li(a0, Operand(Smi::FromInt(strict_mode)));
1599 __ Push(a1, a0);
1600
1601 // Do tail-call to runtime routine.
1602 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001603}
1604
1605
ager@chromium.org5c838252010-02-19 08:53:10 +00001606#undef __
1607
lrn@chromium.org7516f052011-03-30 08:52:27 +00001608
1609Condition CompareIC::ComputeCondition(Token::Value op) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001610 switch (op) {
1611 case Token::EQ_STRICT:
1612 case Token::EQ:
1613 return eq;
1614 case Token::LT:
1615 return lt;
1616 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001617 return gt;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001618 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001619 return le;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001620 case Token::GTE:
1621 return ge;
1622 default:
1623 UNREACHABLE();
1624 return kNoCondition;
1625 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001626}
1627
1628
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001629bool CompareIC::HasInlinedSmiCode(Address address) {
1630 // The address of the instruction following the call.
1631 Address andi_instruction_address =
1632 address + Assembler::kCallTargetAddressOffset;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001633
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001634 // If the instruction following the call is not a andi at, rx, #yyy, nothing
1635 // was inlined.
1636 Instr instr = Assembler::instr_at(andi_instruction_address);
1637 return Assembler::IsAndImmediate(instr) &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001638 Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code());
lrn@chromium.org7516f052011-03-30 08:52:27 +00001639}
1640
1641
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001642void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001643 Address andi_instruction_address =
1644 address + Assembler::kCallTargetAddressOffset;
1645
1646 // If the instruction following the call is not a andi at, rx, #yyy, nothing
1647 // was inlined.
1648 Instr instr = Assembler::instr_at(andi_instruction_address);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001649 if (!(Assembler::IsAndImmediate(instr) &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001650 Assembler::GetRt(instr) == static_cast<uint32_t>(zero_reg.code()))) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001651 return;
1652 }
1653
1654 // The delta to the start of the map check instruction and the
1655 // condition code uses at the patched jump.
1656 int delta = Assembler::GetImmediate16(instr);
1657 delta += Assembler::GetRs(instr) * kImm16Mask;
1658 // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
1659 // signals that nothing was inlined.
1660 if (delta == 0) {
1661 return;
1662 }
1663
1664#ifdef DEBUG
1665 if (FLAG_trace_ic) {
1666 PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
1667 address, andi_instruction_address, delta);
1668 }
1669#endif
1670
1671 Address patch_address =
1672 andi_instruction_address - delta * Instruction::kInstrSize;
1673 Instr instr_at_patch = Assembler::instr_at(patch_address);
1674 Instr branch_instr =
1675 Assembler::instr_at(patch_address + Instruction::kInstrSize);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00001676 // This is patching a conditional "jump if not smi/jump if smi" site.
1677 // Enabling by changing from
1678 // andi at, rx, 0
1679 // Branch <target>, eq, at, Operand(zero_reg)
1680 // to:
1681 // andi at, rx, #kSmiTagMask
1682 // Branch <target>, ne, at, Operand(zero_reg)
1683 // and vice-versa to be disabled again.
1684 CodePatcher patcher(patch_address, 2);
1685 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
1686 if (check == ENABLE_INLINED_SMI_CHECK) {
1687 ASSERT(Assembler::IsAndImmediate(instr_at_patch));
1688 ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
1689 patcher.masm()->andi(at, reg, kSmiTagMask);
1690 } else {
1691 ASSERT(check == DISABLE_INLINED_SMI_CHECK);
1692 ASSERT(Assembler::IsAndImmediate(instr_at_patch));
1693 patcher.masm()->andi(at, reg, 0);
1694 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001695 ASSERT(Assembler::IsBranch(branch_instr));
1696 if (Assembler::IsBeq(branch_instr)) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001697 patcher.ChangeBranchCondition(ne);
1698 } else {
1699 ASSERT(Assembler::IsBne(branch_instr));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001700 patcher.ChangeBranchCondition(eq);
1701 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001702}
1703
1704
ager@chromium.org5c838252010-02-19 08:53:10 +00001705} } // namespace v8::internal
1706
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001707#endif // V8_TARGET_ARCH_MIPS