blob: 36d71151418b4d35c03076c5f4e13c511b26404d [file] [log] [blame]
karlklose@chromium.org83a47282011-05-11 11:54:09 +00001// Copyright 2011 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.
64static void GenerateStringDictionaryReceiverCheck(MacroAssembler* masm,
65 Register receiver,
66 Register elements,
67 Register scratch0,
68 Register scratch1,
69 Label* miss) {
70 // 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.
132 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
133 miss,
134 &done,
135 elements,
136 name,
137 scratch1,
138 scratch2);
139
140 // If probing finds an entry check that the value is a normal
141 // property.
142 __ bind(&done); // scratch2 == elements + 4 * index.
143 const int kElementsStartOffset = StringDictionary::kHeaderSize +
144 StringDictionary::kElementsStartIndex * kPointerSize;
145 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
146 __ lw(scratch1, FieldMemOperand(scratch2, kDetailsOffset));
147 __ And(at,
148 scratch1,
149 Operand(PropertyDetails::TypeField::mask() << kSmiTagSize));
150 __ 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.
185 StringDictionaryLookupStub::GeneratePositiveLookup(masm,
186 miss,
187 &done,
188 elements,
189 name,
190 scratch1,
191 scratch2);
192
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.
196 const int kElementsStartOffset = StringDictionary::kHeaderSize +
197 StringDictionary::kElementsStartIndex * kPointerSize;
198 const int kDetailsOffset = kElementsStartOffset + 2 * kPointerSize;
199 const int kTypeAndReadOnlyMask
200 = (PropertyDetails::TypeField::mask() |
201 PropertyDetails::AttributesField::encode(READ_ONLY)) << kSmiTagSize;
202 __ 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);
213 __ RecordWrite(elements, scratch2, scratch1);
214}
215
216
217static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
218 Label* miss,
219 Register elements,
220 Register key,
221 Register result,
222 Register reg0,
223 Register reg1,
224 Register reg2) {
225 // Register use:
226 //
227 // elements - holds the slow-case elements of the receiver on entry.
228 // Unchanged unless 'result' is the same register.
229 //
230 // key - holds the smi key on entry.
231 // Unchanged unless 'result' is the same register.
232 //
233 //
234 // result - holds the result on exit if the load succeeded.
235 // Allowed to be the same as 'key' or 'result'.
236 // Unchanged on bailout so 'key' or 'result' can be used
237 // in further computation.
238 //
239 // Scratch registers:
240 //
241 // reg0 - holds the untagged key on entry and holds the hash once computed.
242 //
243 // reg1 - Used to hold the capacity mask of the dictionary.
244 //
245 // reg2 - Used for the index into the dictionary.
246 // at - Temporary (avoid MacroAssembler instructions also using 'at').
247 Label done;
248
249 // Compute the hash code from the untagged key. This must be kept in sync
250 // with ComputeIntegerHash in utils.h.
251 //
252 // hash = ~hash + (hash << 15);
253 __ nor(reg1, reg0, zero_reg);
254 __ sll(at, reg0, 15);
255 __ addu(reg0, reg1, at);
256
257 // hash = hash ^ (hash >> 12);
258 __ srl(at, reg0, 12);
259 __ xor_(reg0, reg0, at);
260
261 // hash = hash + (hash << 2);
262 __ sll(at, reg0, 2);
263 __ addu(reg0, reg0, at);
264
265 // hash = hash ^ (hash >> 4);
266 __ srl(at, reg0, 4);
267 __ xor_(reg0, reg0, at);
268
269 // hash = hash * 2057;
270 __ li(reg1, Operand(2057));
271 __ mul(reg0, reg0, reg1);
272
273 // hash = hash ^ (hash >> 16);
274 __ srl(at, reg0, 16);
275 __ xor_(reg0, reg0, at);
276
277 // Compute the capacity mask.
278 __ lw(reg1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset));
279 __ sra(reg1, reg1, kSmiTagSize);
280 __ Subu(reg1, reg1, Operand(1));
281
282 // Generate an unrolled loop that performs a few probes before giving up.
283 static const int kProbes = 4;
284 for (int i = 0; i < kProbes; i++) {
285 // Use reg2 for index calculations and keep the hash intact in reg0.
286 __ mov(reg2, reg0);
287 // Compute the masked index: (hash + i + i * i) & mask.
288 if (i > 0) {
289 __ Addu(reg2, reg2, Operand(NumberDictionary::GetProbeOffset(i)));
290 }
291 __ and_(reg2, reg2, reg1);
292
293 // Scale the index by multiplying by the element size.
294 ASSERT(NumberDictionary::kEntrySize == 3);
295 __ sll(at, reg2, 1); // 2x.
296 __ addu(reg2, reg2, at); // reg2 = reg2 * 3.
297
298 // Check if the key is identical to the name.
299 __ sll(at, reg2, kPointerSizeLog2);
300 __ addu(reg2, elements, at);
301
302 __ lw(at, FieldMemOperand(reg2, NumberDictionary::kElementsStartOffset));
303 if (i != kProbes - 1) {
304 __ Branch(&done, eq, key, Operand(at));
305 } else {
306 __ Branch(miss, ne, key, Operand(at));
307 }
308 }
309
310 __ bind(&done);
311 // Check that the value is a normal property.
312 // reg2: elements + (index * kPointerSize).
313 const int kDetailsOffset =
314 NumberDictionary::kElementsStartOffset + 2 * kPointerSize;
315 __ lw(reg1, FieldMemOperand(reg2, kDetailsOffset));
316 __ And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask())));
317 __ Branch(miss, ne, at, Operand(zero_reg));
318
319 // Get the value at the masked, scaled index and return.
320 const int kValueOffset =
321 NumberDictionary::kElementsStartOffset + kPointerSize;
322 __ lw(result, FieldMemOperand(reg2, kValueOffset));
323}
324
325
ager@chromium.org5c838252010-02-19 08:53:10 +0000326void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000327 // ----------- S t a t e -------------
328 // -- a2 : name
329 // -- ra : return address
330 // -- a0 : receiver
331 // -- sp[0] : receiver
332 // -----------------------------------
333 Label miss;
334
335 StubCompiler::GenerateLoadArrayLength(masm, a0, a3, &miss);
336 __ bind(&miss);
337 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
ager@chromium.org5c838252010-02-19 08:53:10 +0000338}
339
340
lrn@chromium.org7516f052011-03-30 08:52:27 +0000341void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000342 // ----------- S t a t e -------------
343 // -- a2 : name
344 // -- lr : return address
345 // -- a0 : receiver
346 // -- sp[0] : receiver
347 // -----------------------------------
348 Label miss;
349
350 StubCompiler::GenerateLoadStringLength(masm, a0, a1, a3, &miss,
351 support_wrappers);
352 // Cache miss: Jump to runtime.
353 __ bind(&miss);
354 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
ager@chromium.org5c838252010-02-19 08:53:10 +0000355}
356
357
358void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000359 // ----------- S t a t e -------------
360 // -- a2 : name
361 // -- lr : return address
362 // -- a0 : receiver
363 // -- sp[0] : receiver
364 // -----------------------------------
365 Label miss;
366
367 StubCompiler::GenerateLoadFunctionPrototype(masm, a0, a1, a3, &miss);
368 __ bind(&miss);
369 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
370}
371
372
373// Checks the receiver for special cases (value type, slow case bits).
374// Falls through for regular JS object.
375static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
376 Register receiver,
377 Register map,
378 Register scratch,
379 int interceptor_bit,
380 Label* slow) {
381 // Check that the object isn't a smi.
382 __ JumpIfSmi(receiver, slow);
383 // Get the map of the receiver.
384 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
385 // Check bit field.
386 __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
387 __ And(at, scratch, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
388 __ Branch(slow, ne, at, Operand(zero_reg));
389 // Check that the object is some kind of JS object EXCEPT JS Value type.
390 // In the case that the object is a value-wrapper object,
391 // we enter the runtime system to make sure that indexing into string
392 // objects work as intended.
393 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
394 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
395 __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
396}
397
398
399// Loads an indexed element from a fast case array.
400// If not_fast_array is NULL, doesn't perform the elements map check.
401static void GenerateFastArrayLoad(MacroAssembler* masm,
402 Register receiver,
403 Register key,
404 Register elements,
405 Register scratch1,
406 Register scratch2,
407 Register result,
408 Label* not_fast_array,
409 Label* out_of_range) {
410 // Register use:
411 //
412 // receiver - holds the receiver on entry.
413 // Unchanged unless 'result' is the same register.
414 //
415 // key - holds the smi key on entry.
416 // Unchanged unless 'result' is the same register.
417 //
418 // elements - holds the elements of the receiver on exit.
419 //
420 // result - holds the result on exit if the load succeeded.
421 // Allowed to be the the same as 'receiver' or 'key'.
422 // Unchanged on bailout so 'receiver' and 'key' can be safely
423 // used by further computation.
424 //
425 // Scratch registers:
426 //
427 // scratch1 - used to hold elements map and elements length.
428 // Holds the elements map if not_fast_array branch is taken.
429 //
430 // scratch2 - used to hold the loaded value.
431
432 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
433 if (not_fast_array != NULL) {
434 // Check that the object is in fast mode (not dictionary).
435 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
436 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
437 __ Branch(not_fast_array, ne, scratch1, Operand(at));
438 } else {
439 __ AssertFastElements(elements);
440 }
441
442 // Check that the key (index) is within bounds.
443 __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
444 __ Branch(out_of_range, hs, key, Operand(scratch1));
445
446 // Fast case: Do the load.
447 __ Addu(scratch1, elements,
448 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
449 // The key is a smi.
450 ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
451 __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
452 __ addu(at, at, scratch1);
453 __ lw(scratch2, MemOperand(at));
454
455 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
456 // In case the loaded value is the_hole we have to consult GetProperty
457 // to ensure the prototype chain is searched.
458 __ Branch(out_of_range, eq, scratch2, Operand(at));
459 __ mov(result, scratch2);
460}
461
462
463// Checks whether a key is an array index string or a symbol string.
464// Falls through if a key is a symbol.
465static void GenerateKeyStringCheck(MacroAssembler* masm,
466 Register key,
467 Register map,
468 Register hash,
469 Label* index_string,
470 Label* not_symbol) {
471 // The key is not a smi.
472 // Is it a string?
473 __ GetObjectType(key, map, hash);
474 __ Branch(not_symbol, ge, hash, Operand(FIRST_NONSTRING_TYPE));
475
476 // Is the string an array index, with cached numeric value?
477 __ lw(hash, FieldMemOperand(key, String::kHashFieldOffset));
478 __ And(at, hash, Operand(String::kContainsCachedArrayIndexMask));
479 __ Branch(index_string, eq, at, Operand(zero_reg));
480
481 // Is the string a symbol?
482 // map: key map
483 __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
484 ASSERT(kSymbolTag != 0);
485 __ And(at, hash, Operand(kIsSymbolMask));
486 __ Branch(not_symbol, eq, at, Operand(zero_reg));
ager@chromium.org5c838252010-02-19 08:53:10 +0000487}
488
489
490// Defined in ic.cc.
491Object* CallIC_Miss(Arguments args);
492
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000493// The generated code does not accept smi keys.
494// The generated code falls through if both probes miss.
495static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
496 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000497 Code::Kind kind,
498 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000499 // ----------- S t a t e -------------
500 // -- a1 : receiver
501 // -- a2 : name
502 // -----------------------------------
503 Label number, non_number, non_string, boolean, probe, miss;
504
505 // Probe the stub cache.
506 Code::Flags flags = Code::ComputeFlags(kind,
507 NOT_IN_LOOP,
508 MONOMORPHIC,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000509 extra_ic_state,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000510 NORMAL,
511 argc);
512 Isolate::Current()->stub_cache()->GenerateProbe(
513 masm, flags, a1, a2, a3, t0, t1);
514
515 // If the stub cache probing failed, the receiver might be a value.
516 // For value objects, we use the map of the prototype objects for
517 // the corresponding JSValue for the cache and that is what we need
518 // to probe.
519 //
520 // Check for number.
521 __ JumpIfSmi(a1, &number, t1);
522 __ GetObjectType(a1, a3, a3);
523 __ Branch(&non_number, ne, a3, Operand(HEAP_NUMBER_TYPE));
524 __ bind(&number);
525 StubCompiler::GenerateLoadGlobalFunctionPrototype(
526 masm, Context::NUMBER_FUNCTION_INDEX, a1);
527 __ Branch(&probe);
528
529 // Check for string.
530 __ bind(&non_number);
531 __ Branch(&non_string, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
532 StubCompiler::GenerateLoadGlobalFunctionPrototype(
533 masm, Context::STRING_FUNCTION_INDEX, a1);
534 __ Branch(&probe);
535
536 // Check for boolean.
537 __ bind(&non_string);
538 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
539 __ Branch(&boolean, eq, a1, Operand(t0));
540 __ LoadRoot(t1, Heap::kFalseValueRootIndex);
541 __ Branch(&miss, ne, a1, Operand(t1));
542 __ bind(&boolean);
543 StubCompiler::GenerateLoadGlobalFunctionPrototype(
544 masm, Context::BOOLEAN_FUNCTION_INDEX, a1);
545
546 // Probe the stub cache for the value object.
547 __ bind(&probe);
548 Isolate::Current()->stub_cache()->GenerateProbe(
549 masm, flags, a1, a2, a3, t0, t1);
550
551 __ bind(&miss);
552}
553
554
555static void GenerateFunctionTailCall(MacroAssembler* masm,
556 int argc,
557 Label* miss,
558 Register scratch) {
559 // a1: function
560
561 // Check that the value isn't a smi.
562 __ JumpIfSmi(a1, miss);
563
564 // Check that the value is a JSFunction.
565 __ GetObjectType(a1, scratch, scratch);
566 __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
567
568 // Invoke the function.
569 ParameterCount actual(argc);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000570 __ InvokeFunction(a1, actual, JUMP_FUNCTION,
571 NullCallWrapper(), CALL_AS_METHOD);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000572}
573
574
575static void GenerateCallNormal(MacroAssembler* masm, int argc) {
576 // ----------- S t a t e -------------
577 // -- a2 : name
578 // -- ra : return address
579 // -----------------------------------
580 Label miss;
581
582 // Get the receiver of the function from the stack into a1.
583 __ lw(a1, MemOperand(sp, argc * kPointerSize));
584
585 GenerateStringDictionaryReceiverCheck(masm, a1, a0, a3, t0, &miss);
586
587 // a0: elements
588 // Search the dictionary - put result in register a1.
589 GenerateDictionaryLoad(masm, &miss, a0, a2, a1, a3, t0);
590
591 GenerateFunctionTailCall(masm, argc, &miss, t0);
592
593 // Cache miss: Jump to runtime.
594 __ bind(&miss);
595}
596
597
danno@chromium.org40cb8782011-05-25 07:58:50 +0000598static void GenerateCallMiss(MacroAssembler* masm,
599 int argc,
600 IC::UtilityId id,
601 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000602 // ----------- S t a t e -------------
603 // -- a2 : name
604 // -- ra : return address
605 // -----------------------------------
606 Isolate* isolate = masm->isolate();
607
608 if (id == IC::kCallIC_Miss) {
609 __ IncrementCounter(isolate->counters()->call_miss(), 1, a3, t0);
610 } else {
611 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, a3, t0);
612 }
613
614 // Get the receiver of the function from the stack.
615 __ lw(a3, MemOperand(sp, argc*kPointerSize));
616
617 __ EnterInternalFrame();
618
619 // Push the receiver and the name of the function.
620 __ Push(a3, a2);
621
622 // Call the entry.
623 __ li(a0, Operand(2));
624 __ li(a1, Operand(ExternalReference(IC_Utility(id), isolate)));
625
626 CEntryStub stub(1);
627 __ CallStub(&stub);
628
629 // Move result to a1 and leave the internal frame.
630 __ mov(a1, v0);
631 __ LeaveInternalFrame();
632
633 // Check if the receiver is a global object of some sort.
634 // This can happen only for regular CallIC but not KeyedCallIC.
635 if (id == IC::kCallIC_Miss) {
636 Label invoke, global;
637 __ lw(a2, MemOperand(sp, argc * kPointerSize));
638 __ andi(t0, a2, kSmiTagMask);
639 __ Branch(&invoke, eq, t0, Operand(zero_reg));
640 __ GetObjectType(a2, a3, a3);
641 __ Branch(&global, eq, a3, Operand(JS_GLOBAL_OBJECT_TYPE));
642 __ Branch(&invoke, ne, a3, Operand(JS_BUILTINS_OBJECT_TYPE));
643
644 // Patch the receiver on the stack.
645 __ bind(&global);
646 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
647 __ sw(a2, MemOperand(sp, argc * kPointerSize));
648 __ bind(&invoke);
649 }
650 // Invoke the function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000651 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
652 ? CALL_AS_FUNCTION
653 : CALL_AS_METHOD;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000654 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000655 __ InvokeFunction(a1,
656 actual,
657 JUMP_FUNCTION,
658 NullCallWrapper(),
659 call_kind);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000660}
661
lrn@chromium.org7516f052011-03-30 08:52:27 +0000662
danno@chromium.org40cb8782011-05-25 07:58:50 +0000663void CallIC::GenerateMiss(MacroAssembler* masm,
664 int argc,
665 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000666 // ----------- S t a t e -------------
667 // -- a2 : name
668 // -- ra : return address
669 // -----------------------------------
670
danno@chromium.org40cb8782011-05-25 07:58:50 +0000671 GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000672}
673
674
danno@chromium.org40cb8782011-05-25 07:58:50 +0000675void CallIC::GenerateMegamorphic(MacroAssembler* masm,
676 int argc,
677 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000678 // ----------- S t a t e -------------
679 // -- a2 : name
680 // -- ra : return address
681 // -----------------------------------
682
683 // Get the receiver of the function from the stack into a1.
684 __ lw(a1, MemOperand(sp, argc * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000685 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
686 GenerateMiss(masm, argc, extra_ic_state);
ager@chromium.org5c838252010-02-19 08:53:10 +0000687}
688
689
690void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000691 // ----------- S t a t e -------------
692 // -- a2 : name
693 // -- ra : return address
694 // -----------------------------------
695
696 GenerateCallNormal(masm, argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000697 GenerateMiss(masm, argc, Code::kNoExtraICState);
ager@chromium.org5c838252010-02-19 08:53:10 +0000698}
699
lrn@chromium.org7516f052011-03-30 08:52:27 +0000700
701void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000702 // ----------- S t a t e -------------
703 // -- a2 : name
704 // -- ra : return address
705 // -----------------------------------
706
danno@chromium.org40cb8782011-05-25 07:58:50 +0000707 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
ager@chromium.org5c838252010-02-19 08:53:10 +0000708}
709
lrn@chromium.org7516f052011-03-30 08:52:27 +0000710
711void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000712 // ----------- S t a t e -------------
713 // -- a2 : name
714 // -- ra : return address
715 // -----------------------------------
716
717 // Get the receiver of the function from the stack into a1.
718 __ lw(a1, MemOperand(sp, argc * kPointerSize));
719
720 Label do_call, slow_call, slow_load, slow_reload_receiver;
721 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
722 Label index_smi, index_string;
723
724 // Check that the key is a smi.
725 __ JumpIfNotSmi(a2, &check_string);
726 __ bind(&index_smi);
727 // Now the key is known to be a smi. This place is also jumped to from below
728 // where a numeric string is converted to a smi.
729
730 GenerateKeyedLoadReceiverCheck(
731 masm, a1, a0, a3, Map::kHasIndexedInterceptor, &slow_call);
732
733 GenerateFastArrayLoad(
734 masm, a1, a2, t0, a3, a0, a1, &check_number_dictionary, &slow_load);
735 Counters* counters = masm->isolate()->counters();
736 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, a0, a3);
737
738 __ bind(&do_call);
739 // receiver in a1 is not used after this point.
740 // a2: key
741 // a1: function
742
743 GenerateFunctionTailCall(masm, argc, &slow_call, a0);
744
745 __ bind(&check_number_dictionary);
746 // a2: key
747 // a3: elements map
748 // t0: elements pointer
749 // Check whether the elements is a number dictionary.
750 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
751 __ Branch(&slow_load, ne, a3, Operand(at));
752 __ sra(a0, a2, kSmiTagSize);
753 // a0: untagged index
754 GenerateNumberDictionaryLoad(masm, &slow_load, t0, a2, a1, a0, a3, t1);
755 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3);
756 __ jmp(&do_call);
757
758 __ bind(&slow_load);
759 // This branch is taken when calling KeyedCallIC_Miss is neither required
760 // nor beneficial.
761 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3);
762 __ EnterInternalFrame();
763 __ push(a2); // Save the key.
764 __ Push(a1, a2); // Pass the receiver and the key.
765 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
766 __ pop(a2); // Restore the key.
767 __ LeaveInternalFrame();
768 __ mov(a1, v0);
769 __ jmp(&do_call);
770
771 __ bind(&check_string);
772 GenerateKeyStringCheck(masm, a2, a0, a3, &index_string, &slow_call);
773
774 // The key is known to be a symbol.
775 // If the receiver is a regular JS object with slow properties then do
776 // a quick inline probe of the receiver's dictionary.
777 // Otherwise do the monomorphic cache probe.
778 GenerateKeyedLoadReceiverCheck(
779 masm, a1, a0, a3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
780
781 __ lw(a0, FieldMemOperand(a1, JSObject::kPropertiesOffset));
782 __ lw(a3, FieldMemOperand(a0, HeapObject::kMapOffset));
783 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
784 __ Branch(&lookup_monomorphic_cache, ne, a3, Operand(at));
785
786 GenerateDictionaryLoad(masm, &slow_load, a0, a2, a1, a3, t0);
787 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, a0, a3);
788 __ jmp(&do_call);
789
790 __ bind(&lookup_monomorphic_cache);
791 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000792 GenerateMonomorphicCacheProbe(masm,
793 argc,
794 Code::KEYED_CALL_IC,
795 Code::kNoExtraICState);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000796 // Fall through on miss.
797
798 __ bind(&slow_call);
799 // This branch is taken if:
800 // - the receiver requires boxing or access check,
801 // - the key is neither smi nor symbol,
802 // - the value loaded is not a function,
803 // - there is hope that the runtime will create a monomorphic call stub,
804 // that will get fetched next time.
805 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, a0, a3);
806 GenerateMiss(masm, argc);
807
808 __ bind(&index_string);
809 __ IndexFromHash(a3, a2);
810 // Now jump to the place where smi keys are handled.
811 __ jmp(&index_smi);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000812}
813
814
815void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000816 // ----------- S t a t e -------------
817 // -- a2 : name
818 // -- ra : return address
819 // -----------------------------------
820
821 // Check if the name is a string.
822 Label miss;
823 __ JumpIfSmi(a2, &miss);
824 __ IsObjectJSStringType(a2, a0, &miss);
825
826 GenerateCallNormal(masm, argc);
827 __ bind(&miss);
828 GenerateMiss(masm, argc);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000829}
830
831
ager@chromium.org5c838252010-02-19 08:53:10 +0000832// Defined in ic.cc.
833Object* LoadIC_Miss(Arguments args);
834
835void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000836 // ----------- S t a t e -------------
837 // -- a2 : name
838 // -- ra : return address
839 // -- a0 : receiver
840 // -- sp[0] : receiver
841 // -----------------------------------
842
843 // Probe the stub cache.
844 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
845 NOT_IN_LOOP,
846 MONOMORPHIC);
847 Isolate::Current()->stub_cache()->GenerateProbe(
848 masm, flags, a0, a2, a3, t0, t1);
849
850 // Cache miss: Jump to runtime.
851 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +0000852}
853
854
855void LoadIC::GenerateNormal(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000856 // ----------- S t a t e -------------
857 // -- a2 : name
858 // -- lr : return address
859 // -- a0 : receiver
860 // -- sp[0] : receiver
861 // -----------------------------------
862 Label miss;
863
864 GenerateStringDictionaryReceiverCheck(masm, a0, a1, a3, t0, &miss);
865
866 // a1: elements
867 GenerateDictionaryLoad(masm, &miss, a1, a2, v0, a3, t0);
868 __ Ret();
869
870 // Cache miss: Jump to runtime.
871 __ bind(&miss);
872 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +0000873}
874
875
876void LoadIC::GenerateMiss(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000877 // ----------- S t a t e -------------
878 // -- a2 : name
879 // -- ra : return address
880 // -- a0 : receiver
881 // -- sp[0] : receiver
882 // -----------------------------------
883 Isolate* isolate = masm->isolate();
884
885 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
886
887 __ mov(a3, a0);
888 __ Push(a3, a2);
889
890 // Perform tail call to the entry.
891 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
892 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000893}
894
895
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000896static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
897 Register object,
898 Register key,
899 Register scratch1,
900 Register scratch2,
901 Register scratch3,
902 Label* unmapped_case,
903 Label* slow_case) {
904 Heap* heap = masm->isolate()->heap();
905
906 // Check that the receiver isn't a smi.
907 __ JumpIfSmi(object, slow_case);
908
909 // Check that the key is a positive smi.
910 __ And(scratch1, key, Operand(0x8000001));
911 __ Branch(slow_case, ne, scratch1, Operand(zero_reg));
912
913 // Load the elements into scratch1 and check its map.
914 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
915 __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
916 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
917
918 // Check if element is in the range of mapped arguments. If not, jump
919 // to the unmapped lookup with the parameter map in scratch1.
920 __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
921 __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2)));
922 __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2));
923
924 // Load element index and check whether it is the hole.
925 const int kOffset =
926 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
927
928 __ li(scratch3, Operand(kPointerSize >> 1));
929 __ mul(scratch3, key, scratch3);
930 __ Addu(scratch3, scratch3, Operand(kOffset));
931
932 __ Addu(scratch2, scratch1, scratch3);
933 __ lw(scratch2, MemOperand(scratch2));
934 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
935 __ Branch(unmapped_case, eq, scratch2, Operand(scratch3));
936
937 // Load value from context and return it. We can reuse scratch1 because
938 // we do not jump to the unmapped lookup (which requires the parameter
939 // map in scratch1).
940 __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
941 __ li(scratch3, Operand(kPointerSize >> 1));
942 __ mul(scratch3, scratch2, scratch3);
943 __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
944 __ Addu(scratch2, scratch1, scratch3);
945 return MemOperand(scratch2);
946}
947
948
949static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
950 Register key,
951 Register parameter_map,
952 Register scratch,
953 Label* slow_case) {
954 // Element is in arguments backing store, which is referenced by the
955 // second element of the parameter_map. The parameter_map register
956 // must be loaded with the parameter map of the arguments object and is
957 // overwritten.
958 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
959 Register backing_store = parameter_map;
960 __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
961 __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
962 __ Branch(slow_case, Ugreater_equal, key, Operand(scratch));
963 __ li(scratch, Operand(kPointerSize >> 1));
964 __ mul(scratch, key, scratch);
965 __ Addu(scratch,
966 scratch,
967 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
968 __ Addu(scratch, backing_store, scratch);
969 return MemOperand(scratch);
970}
971
972
973void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
974 // ---------- S t a t e --------------
975 // -- lr : return address
976 // -- a0 : key
977 // -- a1 : receiver
978 // -----------------------------------
979 Label slow, notin;
980 MemOperand mapped_location =
981 GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, &notin, &slow);
982 __ lw(v0, mapped_location);
983 __ Ret();
984 __ bind(&notin);
985 // The unmapped lookup expects that the parameter map is in a2.
986 MemOperand unmapped_location =
987 GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow);
988 __ lw(a2, unmapped_location);
989 __ Branch(&slow, eq, a2, Operand(a3));
990 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
991 __ mov(v0, a2);
992 __ Ret();
993 __ bind(&slow);
994 GenerateMiss(masm, false);
995}
996
997
998void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
999 // ---------- S t a t e --------------
1000 // -- a0 : value
1001 // -- a1 : key
1002 // -- a2 : receiver
1003 // -- lr : return address
1004 // -----------------------------------
1005 Label slow, notin;
1006 MemOperand mapped_location =
1007 GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, &notin, &slow);
1008 __ sw(a0, mapped_location);
ager@chromium.org04921a82011-06-27 13:21:41 +00001009 // Verify mapped_location MemOperand is register, with no offset.
1010 ASSERT_EQ(mapped_location.offset(), 0);
1011 __ RecordWrite(a3, mapped_location.rm(), t5);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001012 __ Ret(USE_DELAY_SLOT);
1013 __ mov(v0, a0); // (In delay slot) return the value stored in v0.
1014 __ bind(&notin);
1015 // The unmapped lookup expects that the parameter map is in a3.
1016 MemOperand unmapped_location =
1017 GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
1018 __ sw(a0, unmapped_location);
ager@chromium.org04921a82011-06-27 13:21:41 +00001019 ASSERT_EQ(unmapped_location.offset(), 0);
1020 __ RecordWrite(a3, unmapped_location.rm(), t5);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001021 __ Ret(USE_DELAY_SLOT);
1022 __ mov(v0, a0); // (In delay slot) return the value stored in v0.
1023 __ bind(&slow);
1024 GenerateMiss(masm, false);
1025}
1026
1027
1028void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
1029 int argc) {
1030 // ----------- S t a t e -------------
1031 // -- a2 : name
1032 // -- lr : return address
1033 // -----------------------------------
1034 Label slow, notin;
1035 // Load receiver.
1036 __ lw(a1, MemOperand(sp, argc * kPointerSize));
1037 MemOperand mapped_location =
1038 GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, &notin, &slow);
1039 __ lw(a1, mapped_location);
1040 GenerateFunctionTailCall(masm, argc, &slow, a3);
1041 __ bind(&notin);
1042 // The unmapped lookup expects that the parameter map is in a3.
1043 MemOperand unmapped_location =
1044 GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow);
1045 __ lw(a1, unmapped_location);
1046 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
1047 __ Branch(&slow, eq, a1, Operand(a3));
1048 GenerateFunctionTailCall(masm, argc, &slow, a3);
1049 __ bind(&slow);
1050 GenerateMiss(masm, argc);
1051}
1052
1053
1054Object* KeyedLoadIC_Miss(Arguments args);
1055
1056
danno@chromium.org40cb8782011-05-25 07:58:50 +00001057void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001058 // ---------- S t a t e --------------
1059 // -- ra : return address
1060 // -- a0 : key
1061 // -- a1 : receiver
1062 // -----------------------------------
1063 Isolate* isolate = masm->isolate();
1064
1065 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
1066
1067 __ Push(a1, a0);
1068
danno@chromium.org40cb8782011-05-25 07:58:50 +00001069 // Perform tail call to the entry.
1070 ExternalReference ref = force_generic
1071 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
1072 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
1073
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001074 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001075}
1076
1077
lrn@chromium.org7516f052011-03-30 08:52:27 +00001078void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001079 // ---------- S t a t e --------------
1080 // -- ra : return address
1081 // -- a0 : key
1082 // -- a1 : receiver
1083 // -----------------------------------
1084
1085 __ Push(a1, a0);
1086
1087 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001088}
1089
1090
ager@chromium.org5c838252010-02-19 08:53:10 +00001091void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001092 // ---------- S t a t e --------------
1093 // -- ra : return address
1094 // -- a0 : key
1095 // -- a1 : receiver
1096 // -----------------------------------
1097 Label slow, check_string, index_smi, index_string, property_array_property;
1098 Label probe_dictionary, check_number_dictionary;
1099
1100 Register key = a0;
1101 Register receiver = a1;
1102
1103 Isolate* isolate = masm->isolate();
1104
1105 // Check that the key is a smi.
1106 __ JumpIfNotSmi(key, &check_string);
1107 __ bind(&index_smi);
1108 // Now the key is known to be a smi. This place is also jumped to from below
1109 // where a numeric string is converted to a smi.
1110
1111 GenerateKeyedLoadReceiverCheck(
1112 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
1113
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001114 // Check the receiver's map to see if it has fast elements.
1115 __ CheckFastElements(a2, a3, &check_number_dictionary);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001116
1117 GenerateFastArrayLoad(
1118 masm, receiver, key, t0, a3, a2, v0, NULL, &slow);
1119
1120 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3);
1121 __ Ret();
1122
1123 __ bind(&check_number_dictionary);
1124 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
1125 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset));
1126
1127 // Check whether the elements is a number dictionary.
1128 // a0: key
1129 // a3: elements map
1130 // t0: elements
1131 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
1132 __ Branch(&slow, ne, a3, Operand(at));
1133 __ sra(a2, a0, kSmiTagSize);
1134 GenerateNumberDictionaryLoad(masm, &slow, t0, a0, v0, a2, a3, t1);
1135 __ Ret();
1136
1137 // Slow case, key and receiver still in a0 and a1.
1138 __ bind(&slow);
1139 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
1140 1,
1141 a2,
1142 a3);
1143 GenerateRuntimeGetProperty(masm);
1144
1145 __ bind(&check_string);
1146 GenerateKeyStringCheck(masm, key, a2, a3, &index_string, &slow);
1147
1148 GenerateKeyedLoadReceiverCheck(
1149 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
1150
1151
1152 // If the receiver is a fast-case object, check the keyed lookup
1153 // cache. Otherwise probe the dictionary.
1154 __ lw(a3, FieldMemOperand(a1, JSObject::kPropertiesOffset));
1155 __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
1156 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
1157 __ Branch(&probe_dictionary, eq, t0, Operand(at));
1158
1159 // Load the map of the receiver, compute the keyed lookup cache hash
1160 // based on 32 bits of the map pointer and the string hash.
1161 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1162 __ sra(a3, a2, KeyedLookupCache::kMapHashShift);
1163 __ lw(t0, FieldMemOperand(a0, String::kHashFieldOffset));
1164 __ sra(at, t0, String::kHashShift);
1165 __ xor_(a3, a3, at);
1166 __ And(a3, a3, Operand(KeyedLookupCache::kCapacityMask));
1167
1168 // Load the key (consisting of map and symbol) from the cache and
1169 // check for match.
1170 ExternalReference cache_keys =
1171 ExternalReference::keyed_lookup_cache_keys(isolate);
1172 __ li(t0, Operand(cache_keys));
1173 __ sll(at, a3, kPointerSizeLog2 + 1);
1174 __ addu(t0, t0, at);
1175 __ lw(t1, MemOperand(t0)); // Move t0 to symbol.
1176 __ Addu(t0, t0, Operand(kPointerSize));
1177 __ Branch(&slow, ne, a2, Operand(t1));
1178 __ lw(t1, MemOperand(t0));
1179 __ Branch(&slow, ne, a0, Operand(t1));
1180
1181 // Get field offset.
1182 // a0 : key
1183 // a1 : receiver
1184 // a2 : receiver's map
1185 // a3 : lookup cache index
1186 ExternalReference cache_field_offsets =
1187 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
1188 __ li(t0, Operand(cache_field_offsets));
1189 __ sll(at, a3, kPointerSizeLog2);
1190 __ addu(at, t0, at);
1191 __ lw(t1, MemOperand(at));
1192 __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
1193 __ Subu(t1, t1, t2);
1194 __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
1195
1196 // Load in-object property.
1197 __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset));
1198 __ addu(t2, t2, t1); // Index from start of object.
1199 __ Subu(a1, a1, Operand(kHeapObjectTag)); // Remove the heap tag.
1200 __ sll(at, t2, kPointerSizeLog2);
1201 __ addu(at, a1, at);
1202 __ lw(v0, MemOperand(at));
1203 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1204 1,
1205 a2,
1206 a3);
1207 __ Ret();
1208
1209 // Load property array property.
1210 __ bind(&property_array_property);
1211 __ lw(a1, FieldMemOperand(a1, JSObject::kPropertiesOffset));
1212 __ Addu(a1, a1, FixedArray::kHeaderSize - kHeapObjectTag);
1213 __ sll(t0, t1, kPointerSizeLog2);
1214 __ Addu(t0, t0, a1);
1215 __ lw(v0, MemOperand(t0));
1216 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1217 1,
1218 a2,
1219 a3);
1220 __ Ret();
1221
1222
1223 // Do a quick inline probe of the receiver's dictionary, if it
1224 // exists.
1225 __ bind(&probe_dictionary);
1226 // a1: receiver
1227 // a0: key
1228 // a3: elements
1229 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1230 __ lbu(a2, FieldMemOperand(a2, Map::kInstanceTypeOffset));
1231 GenerateGlobalInstanceTypeCheck(masm, a2, &slow);
1232 // Load the property to v0.
1233 GenerateDictionaryLoad(masm, &slow, a3, a0, v0, a2, t0);
1234 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1235 1,
1236 a2,
1237 a3);
1238 __ Ret();
1239
1240 __ bind(&index_string);
1241 __ IndexFromHash(a3, key);
1242 // Now jump to the place where smi keys are handled.
1243 __ Branch(&index_smi);
ager@chromium.org5c838252010-02-19 08:53:10 +00001244}
1245
1246
1247void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001248 // ---------- S t a t e --------------
1249 // -- ra : return address
1250 // -- a0 : key (index)
1251 // -- a1 : receiver
1252 // -----------------------------------
1253 Label miss;
1254
1255 Register receiver = a1;
1256 Register index = a0;
1257 Register scratch1 = a2;
1258 Register scratch2 = a3;
1259 Register result = v0;
1260
1261 StringCharAtGenerator char_at_generator(receiver,
1262 index,
1263 scratch1,
1264 scratch2,
1265 result,
1266 &miss, // When not a string.
1267 &miss, // When not a number.
1268 &miss, // When index out of range.
1269 STRING_INDEX_IS_ARRAY_INDEX);
1270 char_at_generator.GenerateFast(masm);
1271 __ Ret();
1272
1273 StubRuntimeCallHelper call_helper;
1274 char_at_generator.GenerateSlow(masm, call_helper);
1275
1276 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001277 GenerateMiss(masm, false);
ager@chromium.org5c838252010-02-19 08:53:10 +00001278}
1279
1280
lrn@chromium.org7516f052011-03-30 08:52:27 +00001281void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1282 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001283 // ---------- S t a t e --------------
1284 // -- a0 : value
1285 // -- a1 : key
1286 // -- a2 : receiver
1287 // -- ra : return address
1288 // -----------------------------------
1289
1290 // Push receiver, key and value for runtime call.
1291 __ Push(a2, a1, a0);
1292 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1293 __ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1294 __ Push(a1, a0);
1295
1296 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001297}
1298
1299
1300void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1301 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001302 // ---------- S t a t e --------------
1303 // -- a0 : value
1304 // -- a1 : key
1305 // -- a2 : receiver
1306 // -- ra : return address
1307 // -----------------------------------
1308
1309 Label slow, fast, array, extra, exit;
1310
1311 // Register usage.
1312 Register value = a0;
1313 Register key = a1;
1314 Register receiver = a2;
1315 Register elements = a3; // Elements array of the receiver.
1316 // t0 is used as ip in the arm version.
1317 // t3-t4 are used as temporaries.
1318
1319 // Check that the key is a smi.
1320 __ JumpIfNotSmi(key, &slow);
1321 // Check that the object isn't a smi.
1322 __ JumpIfSmi(receiver, &slow);
1323
1324 // Get the map of the object.
1325 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1326 // Check that the receiver does not require access checks. We need
1327 // to do this because this generic stub does not perform map checks.
1328 __ lbu(t0, FieldMemOperand(t3, Map::kBitFieldOffset));
1329 __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
1330 __ Branch(&slow, ne, t0, Operand(zero_reg));
1331 // Check if the object is a JS array or not.
1332 __ lbu(t3, FieldMemOperand(t3, Map::kInstanceTypeOffset));
1333
1334 __ Branch(&array, eq, t3, Operand(JS_ARRAY_TYPE));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001335 // Check that the object is some kind of JSObject.
1336 __ Branch(&slow, lt, t3, Operand(FIRST_JS_RECEIVER_TYPE));
1337 __ Branch(&slow, eq, t3, Operand(JS_PROXY_TYPE));
1338 __ Branch(&slow, eq, t3, Operand(JS_FUNCTION_PROXY_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001339
1340 // Object case: Check key against length in the elements array.
1341 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1342 // Check that the object is in fast mode and writable.
1343 __ lw(t3, FieldMemOperand(elements, HeapObject::kMapOffset));
1344 __ LoadRoot(t0, Heap::kFixedArrayMapRootIndex);
1345 __ Branch(&slow, ne, t3, Operand(t0));
1346 // Check array bounds. Both the key and the length of FixedArray are smis.
1347 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1348 __ Branch(&fast, lo, key, Operand(t0));
1349 // Fall thru to slow if un-tagged index >= length.
1350
1351 // Slow case, handle jump to runtime.
1352 __ bind(&slow);
1353
1354 // Entry registers are intact.
1355 // a0: value.
1356 // a1: key.
1357 // a2: receiver.
1358
1359 GenerateRuntimeSetProperty(masm, strict_mode);
1360
1361 // Extra capacity case: Check if there is extra capacity to
1362 // perform the store and update the length. Used for adding one
1363 // element to the array by writing to array[array.length].
1364
1365 __ bind(&extra);
1366 // Only support writing to array[array.length].
1367 __ Branch(&slow, ne, key, Operand(t0));
1368 // Check for room in the elements backing store.
1369 // Both the key and the length of FixedArray are smis.
1370 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1371 __ Branch(&slow, hs, key, Operand(t0));
1372 // Calculate key + 1 as smi.
1373 ASSERT_EQ(0, kSmiTag);
1374 __ Addu(t3, key, Operand(Smi::FromInt(1)));
1375 __ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset));
1376 __ Branch(&fast);
1377
1378
1379 // Array case: Get the length and the elements array from the JS
1380 // array. Check that the array is in fast mode (and writable); if it
1381 // is the length is always a smi.
1382
1383 __ bind(&array);
1384 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1385 __ lw(t3, FieldMemOperand(elements, HeapObject::kMapOffset));
1386 __ LoadRoot(t0, Heap::kFixedArrayMapRootIndex);
1387 __ Branch(&slow, ne, t3, Operand(t0));
1388
1389 // Check the key against the length in the array.
1390 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1391 __ Branch(&extra, hs, key, Operand(t0));
1392 // Fall through to fast case.
1393
1394 __ bind(&fast);
1395 // Fast case, store the value to the elements backing store.
1396 __ Addu(t4, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1397 __ sll(t1, key, kPointerSizeLog2 - kSmiTagSize);
1398 __ Addu(t4, t4, Operand(t1));
1399 __ sw(value, MemOperand(t4));
1400 // Skip write barrier if the written value is a smi.
1401 __ JumpIfSmi(value, &exit);
1402
1403 // Update write barrier for the elements array address.
1404 __ Subu(t3, t4, Operand(elements));
1405
1406 __ RecordWrite(elements, Operand(t3), t4, t5);
1407 __ bind(&exit);
1408
1409 __ mov(v0, a0); // Return the value written.
1410 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001411}
1412
1413
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001414void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001415 // ---------- S t a t e --------------
1416 // -- ra : return address
1417 // -- a0 : key
1418 // -- a1 : receiver
1419 // -----------------------------------
1420 Label slow;
1421
1422 // Check that the receiver isn't a smi.
1423 __ JumpIfSmi(a1, &slow);
1424
1425 // Check that the key is an array index, that is Uint32.
1426 __ And(t0, a0, Operand(kSmiTagMask | kSmiSignMask));
1427 __ Branch(&slow, ne, t0, Operand(zero_reg));
1428
1429 // Get the map of the receiver.
1430 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1431
1432 // Check that it has indexed interceptor and access checks
1433 // are not enabled for this object.
1434 __ lbu(a3, FieldMemOperand(a2, Map::kBitFieldOffset));
1435 __ And(a3, a3, Operand(kSlowCaseBitFieldMask));
1436 __ Branch(&slow, ne, a3, Operand(1 << Map::kHasIndexedInterceptor));
1437 // Everything is fine, call runtime.
1438 __ Push(a1, a0); // Receiver, key.
1439
1440 // Perform tail call to the entry.
1441 __ TailCallExternalReference(ExternalReference(
1442 IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1);
1443
1444 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001445 GenerateMiss(masm, false);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001446}
1447
1448
danno@chromium.org40cb8782011-05-25 07:58:50 +00001449void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1450 // ---------- S t a t e --------------
1451 // -- a0 : value
1452 // -- a1 : key
1453 // -- a2 : receiver
1454 // -- ra : return address
1455 // -----------------------------------
1456
1457 // Push receiver, key and value for runtime call.
1458 __ Push(a2, a1, a0);
1459
1460 ExternalReference ref = force_generic
1461 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1462 masm->isolate())
1463 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1464 __ TailCallExternalReference(ref, 3, 1);
1465}
1466
1467
1468void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001469 // ---------- S t a t e --------------
1470 // -- a0 : value
1471 // -- a1 : key
1472 // -- a2 : receiver
1473 // -- ra : return address
1474 // -----------------------------------
1475
1476 // Push receiver, key and value for runtime call.
1477 // We can't use MultiPush as the order of the registers is important.
1478 __ Push(a2, a1, a0);
1479
danno@chromium.org40cb8782011-05-25 07:58:50 +00001480 // The slow case calls into the runtime to complete the store without causing
1481 // an IC miss that would otherwise cause a transition to the generic stub.
1482 ExternalReference ref =
1483 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1484
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001485 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001486}
1487
1488
lrn@chromium.org7516f052011-03-30 08:52:27 +00001489void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1490 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001491 // ----------- S t a t e -------------
1492 // -- a0 : value
1493 // -- a1 : receiver
1494 // -- a2 : name
1495 // -- ra : return address
1496 // -----------------------------------
1497
1498 // Get the receiver from the stack and probe the stub cache.
1499 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1500 NOT_IN_LOOP,
1501 MONOMORPHIC,
1502 strict_mode);
1503 Isolate::Current()->stub_cache()->GenerateProbe(
1504 masm, flags, a1, a2, a3, t0, t1);
1505
1506 // Cache miss: Jump to runtime.
1507 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +00001508}
1509
1510
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001511void StoreIC::GenerateMiss(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001512 // ----------- S t a t e -------------
1513 // -- a0 : value
1514 // -- a1 : receiver
1515 // -- a2 : name
1516 // -- ra : return address
1517 // -----------------------------------
1518
1519 __ Push(a1, a2, a0);
1520 // Perform tail call to the entry.
1521 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
1522 masm->isolate());
1523 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001524}
1525
1526
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001527void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001528 // ----------- S t a t e -------------
1529 // -- a0 : value
1530 // -- a1 : receiver
1531 // -- a2 : name
1532 // -- ra : return address
1533 // -----------------------------------
1534 //
1535 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1536 // (currently anything except for external and pixel arrays which means
1537 // anything with elements of FixedArray type.), but currently is restricted
1538 // to JSArray.
1539 // Value must be a number, but only smis are accepted as the most common case.
1540
1541 Label miss;
1542
1543 Register receiver = a1;
1544 Register value = a0;
1545 Register scratch = a3;
1546
1547 // Check that the receiver isn't a smi.
1548 __ JumpIfSmi(receiver, &miss);
1549
1550 // Check that the object is a JS array.
1551 __ GetObjectType(receiver, scratch, scratch);
1552 __ Branch(&miss, ne, scratch, Operand(JS_ARRAY_TYPE));
1553
1554 // Check that elements are FixedArray.
1555 // We rely on StoreIC_ArrayLength below to deal with all types of
1556 // fast elements (including COW).
1557 __ lw(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1558 __ GetObjectType(scratch, scratch, scratch);
1559 __ Branch(&miss, ne, scratch, Operand(FIXED_ARRAY_TYPE));
1560
1561 // Check that value is a smi.
1562 __ JumpIfNotSmi(value, &miss);
1563
1564 // Prepare tail call to StoreIC_ArrayLength.
1565 __ Push(receiver, value);
1566
1567 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength),
1568 masm->isolate());
1569 __ TailCallExternalReference(ref, 2, 1);
1570
1571 __ bind(&miss);
1572
1573 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +00001574}
1575
lrn@chromium.org7516f052011-03-30 08:52:27 +00001576
1577void StoreIC::GenerateNormal(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001578 // ----------- S t a t e -------------
1579 // -- a0 : value
1580 // -- a1 : receiver
1581 // -- a2 : name
1582 // -- ra : return address
1583 // -----------------------------------
1584 Label miss;
1585
1586 GenerateStringDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss);
1587
1588 GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1);
1589 Counters* counters = masm->isolate()->counters();
1590 __ IncrementCounter(counters->store_normal_hit(), 1, t0, t1);
1591 __ Ret();
1592
1593 __ bind(&miss);
1594 __ IncrementCounter(counters->store_normal_miss(), 1, t0, t1);
1595 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001596}
1597
1598
1599void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1600 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001601 // ----------- S t a t e -------------
1602 // -- a0 : value
1603 // -- a1 : receiver
1604 // -- a2 : name
1605 // -- ra : return address
1606 // -----------------------------------
1607
1608 __ Push(a1, a2, a0);
1609
1610 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1611 __ li(a0, Operand(Smi::FromInt(strict_mode)));
1612 __ Push(a1, a0);
1613
1614 // Do tail-call to runtime routine.
1615 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001616}
1617
1618
ager@chromium.org5c838252010-02-19 08:53:10 +00001619#undef __
1620
lrn@chromium.org7516f052011-03-30 08:52:27 +00001621
1622Condition CompareIC::ComputeCondition(Token::Value op) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001623 switch (op) {
1624 case Token::EQ_STRICT:
1625 case Token::EQ:
1626 return eq;
1627 case Token::LT:
1628 return lt;
1629 case Token::GT:
1630 // Reverse left and right operands to obtain ECMA-262 conversion order.
1631 return lt;
1632 case Token::LTE:
1633 // Reverse left and right operands to obtain ECMA-262 conversion order.
1634 return ge;
1635 case Token::GTE:
1636 return ge;
1637 default:
1638 UNREACHABLE();
1639 return kNoCondition;
1640 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001641}
1642
1643
1644void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001645 HandleScope scope;
1646 Handle<Code> rewritten;
1647 State previous_state = GetState();
1648 State state = TargetState(previous_state, false, x, y);
1649 if (state == GENERIC) {
1650 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0);
1651 rewritten = stub.GetCode();
1652 } else {
1653 ICCompareStub stub(op_, state);
1654 rewritten = stub.GetCode();
1655 }
1656 set_target(*rewritten);
1657
1658#ifdef DEBUG
1659 if (FLAG_trace_ic) {
1660 PrintF("[CompareIC (%s->%s)#%s]\n",
1661 GetStateName(previous_state),
1662 GetStateName(state),
1663 Token::Name(op_));
1664 }
1665#endif
1666
1667 // Activate inlined smi code.
1668 if (previous_state == UNINITIALIZED) {
1669 PatchInlinedSmiCode(address());
1670 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001671}
1672
1673
1674void PatchInlinedSmiCode(Address address) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001675 Address andi_instruction_address =
1676 address + Assembler::kCallTargetAddressOffset;
1677
1678 // If the instruction following the call is not a andi at, rx, #yyy, nothing
1679 // was inlined.
1680 Instr instr = Assembler::instr_at(andi_instruction_address);
1681 if (!Assembler::IsAndImmediate(instr)) {
1682 return;
1683 }
1684
1685 // The delta to the start of the map check instruction and the
1686 // condition code uses at the patched jump.
1687 int delta = Assembler::GetImmediate16(instr);
1688 delta += Assembler::GetRs(instr) * kImm16Mask;
1689 // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
1690 // signals that nothing was inlined.
1691 if (delta == 0) {
1692 return;
1693 }
1694
1695#ifdef DEBUG
1696 if (FLAG_trace_ic) {
1697 PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
1698 address, andi_instruction_address, delta);
1699 }
1700#endif
1701
1702 Address patch_address =
1703 andi_instruction_address - delta * Instruction::kInstrSize;
1704 Instr instr_at_patch = Assembler::instr_at(patch_address);
1705 Instr branch_instr =
1706 Assembler::instr_at(patch_address + Instruction::kInstrSize);
1707 ASSERT(Assembler::IsAndImmediate(instr_at_patch));
1708 ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
1709 ASSERT(Assembler::IsBranch(branch_instr));
1710 if (Assembler::IsBeq(branch_instr)) {
1711 // This is patching a "jump if not smi" site to be active.
1712 // Changing:
1713 // andi at, rx, 0
1714 // Branch <target>, eq, at, Operand(zero_reg)
1715 // to:
1716 // andi at, rx, #kSmiTagMask
1717 // Branch <target>, ne, at, Operand(zero_reg)
1718 CodePatcher patcher(patch_address, 2);
1719 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
1720 patcher.masm()->andi(at, reg, kSmiTagMask);
1721 patcher.ChangeBranchCondition(ne);
1722 } else {
1723 ASSERT(Assembler::IsBne(branch_instr));
1724 // This is patching a "jump if smi" site to be active.
1725 // Changing:
1726 // andi at, rx, 0
1727 // Branch <target>, ne, at, Operand(zero_reg)
1728 // to:
1729 // andi at, rx, #kSmiTagMask
1730 // Branch <target>, eq, at, Operand(zero_reg)
1731 CodePatcher patcher(patch_address, 2);
1732 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
1733 patcher.masm()->andi(at, reg, kSmiTagMask);
1734 patcher.ChangeBranchCondition(eq);
1735 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001736}
1737
1738
ager@chromium.org5c838252010-02-19 08:53:10 +00001739} } // namespace v8::internal
1740
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001741#endif // V8_TARGET_ARCH_MIPS