blob: 5ef35548d635b9f8f3abbc95886bc6ad32d30c22 [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
ager@chromium.org5c838252010-02-19 08:53:10 +0000217void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000218 // ----------- S t a t e -------------
219 // -- a2 : name
220 // -- ra : return address
221 // -- a0 : receiver
222 // -- sp[0] : receiver
223 // -----------------------------------
224 Label miss;
225
226 StubCompiler::GenerateLoadArrayLength(masm, a0, a3, &miss);
227 __ bind(&miss);
228 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
ager@chromium.org5c838252010-02-19 08:53:10 +0000229}
230
231
lrn@chromium.org7516f052011-03-30 08:52:27 +0000232void LoadIC::GenerateStringLength(MacroAssembler* masm, bool support_wrappers) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000233 // ----------- S t a t e -------------
234 // -- a2 : name
235 // -- lr : return address
236 // -- a0 : receiver
237 // -- sp[0] : receiver
238 // -----------------------------------
239 Label miss;
240
241 StubCompiler::GenerateLoadStringLength(masm, a0, a1, a3, &miss,
242 support_wrappers);
243 // Cache miss: Jump to runtime.
244 __ bind(&miss);
245 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
ager@chromium.org5c838252010-02-19 08:53:10 +0000246}
247
248
249void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000250 // ----------- S t a t e -------------
251 // -- a2 : name
252 // -- lr : return address
253 // -- a0 : receiver
254 // -- sp[0] : receiver
255 // -----------------------------------
256 Label miss;
257
258 StubCompiler::GenerateLoadFunctionPrototype(masm, a0, a1, a3, &miss);
259 __ bind(&miss);
260 StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
261}
262
263
264// Checks the receiver for special cases (value type, slow case bits).
265// Falls through for regular JS object.
266static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
267 Register receiver,
268 Register map,
269 Register scratch,
270 int interceptor_bit,
271 Label* slow) {
272 // Check that the object isn't a smi.
273 __ JumpIfSmi(receiver, slow);
274 // Get the map of the receiver.
275 __ lw(map, FieldMemOperand(receiver, HeapObject::kMapOffset));
276 // Check bit field.
277 __ lbu(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
278 __ And(at, scratch, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
279 __ Branch(slow, ne, at, Operand(zero_reg));
280 // Check that the object is some kind of JS object EXCEPT JS Value type.
281 // In the case that the object is a value-wrapper object,
282 // we enter the runtime system to make sure that indexing into string
283 // objects work as intended.
284 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
285 __ lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
286 __ Branch(slow, lt, scratch, Operand(JS_OBJECT_TYPE));
287}
288
289
290// Loads an indexed element from a fast case array.
291// If not_fast_array is NULL, doesn't perform the elements map check.
292static void GenerateFastArrayLoad(MacroAssembler* masm,
293 Register receiver,
294 Register key,
295 Register elements,
296 Register scratch1,
297 Register scratch2,
298 Register result,
299 Label* not_fast_array,
300 Label* out_of_range) {
301 // Register use:
302 //
303 // receiver - holds the receiver on entry.
304 // Unchanged unless 'result' is the same register.
305 //
306 // key - holds the smi key on entry.
307 // Unchanged unless 'result' is the same register.
308 //
309 // elements - holds the elements of the receiver on exit.
310 //
311 // result - holds the result on exit if the load succeeded.
312 // Allowed to be the the same as 'receiver' or 'key'.
313 // Unchanged on bailout so 'receiver' and 'key' can be safely
314 // used by further computation.
315 //
316 // Scratch registers:
317 //
318 // scratch1 - used to hold elements map and elements length.
319 // Holds the elements map if not_fast_array branch is taken.
320 //
321 // scratch2 - used to hold the loaded value.
322
323 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
324 if (not_fast_array != NULL) {
325 // Check that the object is in fast mode (not dictionary).
326 __ lw(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
327 __ LoadRoot(at, Heap::kFixedArrayMapRootIndex);
328 __ Branch(not_fast_array, ne, scratch1, Operand(at));
329 } else {
330 __ AssertFastElements(elements);
331 }
332
333 // Check that the key (index) is within bounds.
334 __ lw(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
335 __ Branch(out_of_range, hs, key, Operand(scratch1));
336
337 // Fast case: Do the load.
338 __ Addu(scratch1, elements,
339 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
340 // The key is a smi.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000341 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize < kPointerSizeLog2);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000342 __ sll(at, key, kPointerSizeLog2 - kSmiTagSize);
343 __ addu(at, at, scratch1);
344 __ lw(scratch2, MemOperand(at));
345
346 __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
347 // In case the loaded value is the_hole we have to consult GetProperty
348 // to ensure the prototype chain is searched.
349 __ Branch(out_of_range, eq, scratch2, Operand(at));
350 __ mov(result, scratch2);
351}
352
353
354// Checks whether a key is an array index string or a symbol string.
355// Falls through if a key is a symbol.
356static void GenerateKeyStringCheck(MacroAssembler* masm,
357 Register key,
358 Register map,
359 Register hash,
360 Label* index_string,
361 Label* not_symbol) {
362 // The key is not a smi.
363 // Is it a string?
364 __ GetObjectType(key, map, hash);
365 __ Branch(not_symbol, ge, hash, Operand(FIRST_NONSTRING_TYPE));
366
367 // Is the string an array index, with cached numeric value?
368 __ lw(hash, FieldMemOperand(key, String::kHashFieldOffset));
369 __ And(at, hash, Operand(String::kContainsCachedArrayIndexMask));
370 __ Branch(index_string, eq, at, Operand(zero_reg));
371
372 // Is the string a symbol?
373 // map: key map
374 __ lbu(hash, FieldMemOperand(map, Map::kInstanceTypeOffset));
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000375 STATIC_ASSERT(kSymbolTag != 0);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000376 __ And(at, hash, Operand(kIsSymbolMask));
377 __ Branch(not_symbol, eq, at, Operand(zero_reg));
ager@chromium.org5c838252010-02-19 08:53:10 +0000378}
379
380
381// Defined in ic.cc.
382Object* CallIC_Miss(Arguments args);
383
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000384// The generated code does not accept smi keys.
385// The generated code falls through if both probes miss.
386static void GenerateMonomorphicCacheProbe(MacroAssembler* masm,
387 int argc,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000388 Code::Kind kind,
389 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000390 // ----------- S t a t e -------------
391 // -- a1 : receiver
392 // -- a2 : name
393 // -----------------------------------
394 Label number, non_number, non_string, boolean, probe, miss;
395
396 // Probe the stub cache.
397 Code::Flags flags = Code::ComputeFlags(kind,
398 NOT_IN_LOOP,
399 MONOMORPHIC,
danno@chromium.org40cb8782011-05-25 07:58:50 +0000400 extra_ic_state,
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000401 NORMAL,
402 argc);
403 Isolate::Current()->stub_cache()->GenerateProbe(
404 masm, flags, a1, a2, a3, t0, t1);
405
406 // If the stub cache probing failed, the receiver might be a value.
407 // For value objects, we use the map of the prototype objects for
408 // the corresponding JSValue for the cache and that is what we need
409 // to probe.
410 //
411 // Check for number.
412 __ JumpIfSmi(a1, &number, t1);
413 __ GetObjectType(a1, a3, a3);
414 __ Branch(&non_number, ne, a3, Operand(HEAP_NUMBER_TYPE));
415 __ bind(&number);
416 StubCompiler::GenerateLoadGlobalFunctionPrototype(
417 masm, Context::NUMBER_FUNCTION_INDEX, a1);
418 __ Branch(&probe);
419
420 // Check for string.
421 __ bind(&non_number);
422 __ Branch(&non_string, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
423 StubCompiler::GenerateLoadGlobalFunctionPrototype(
424 masm, Context::STRING_FUNCTION_INDEX, a1);
425 __ Branch(&probe);
426
427 // Check for boolean.
428 __ bind(&non_string);
429 __ LoadRoot(t0, Heap::kTrueValueRootIndex);
430 __ Branch(&boolean, eq, a1, Operand(t0));
431 __ LoadRoot(t1, Heap::kFalseValueRootIndex);
432 __ Branch(&miss, ne, a1, Operand(t1));
433 __ bind(&boolean);
434 StubCompiler::GenerateLoadGlobalFunctionPrototype(
435 masm, Context::BOOLEAN_FUNCTION_INDEX, a1);
436
437 // Probe the stub cache for the value object.
438 __ bind(&probe);
439 Isolate::Current()->stub_cache()->GenerateProbe(
440 masm, flags, a1, a2, a3, t0, t1);
441
442 __ bind(&miss);
443}
444
445
446static void GenerateFunctionTailCall(MacroAssembler* masm,
447 int argc,
448 Label* miss,
449 Register scratch) {
450 // a1: function
451
452 // Check that the value isn't a smi.
453 __ JumpIfSmi(a1, miss);
454
455 // Check that the value is a JSFunction.
456 __ GetObjectType(a1, scratch, scratch);
457 __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
458
459 // Invoke the function.
460 ParameterCount actual(argc);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000461 __ InvokeFunction(a1, actual, JUMP_FUNCTION,
462 NullCallWrapper(), CALL_AS_METHOD);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000463}
464
465
466static void GenerateCallNormal(MacroAssembler* masm, int argc) {
467 // ----------- S t a t e -------------
468 // -- a2 : name
469 // -- ra : return address
470 // -----------------------------------
471 Label miss;
472
473 // Get the receiver of the function from the stack into a1.
474 __ lw(a1, MemOperand(sp, argc * kPointerSize));
475
476 GenerateStringDictionaryReceiverCheck(masm, a1, a0, a3, t0, &miss);
477
478 // a0: elements
479 // Search the dictionary - put result in register a1.
480 GenerateDictionaryLoad(masm, &miss, a0, a2, a1, a3, t0);
481
482 GenerateFunctionTailCall(masm, argc, &miss, t0);
483
484 // Cache miss: Jump to runtime.
485 __ bind(&miss);
486}
487
488
danno@chromium.org40cb8782011-05-25 07:58:50 +0000489static void GenerateCallMiss(MacroAssembler* masm,
490 int argc,
491 IC::UtilityId id,
492 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000493 // ----------- S t a t e -------------
494 // -- a2 : name
495 // -- ra : return address
496 // -----------------------------------
497 Isolate* isolate = masm->isolate();
498
499 if (id == IC::kCallIC_Miss) {
500 __ IncrementCounter(isolate->counters()->call_miss(), 1, a3, t0);
501 } else {
502 __ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, a3, t0);
503 }
504
505 // Get the receiver of the function from the stack.
506 __ lw(a3, MemOperand(sp, argc*kPointerSize));
507
508 __ EnterInternalFrame();
509
510 // Push the receiver and the name of the function.
511 __ Push(a3, a2);
512
513 // Call the entry.
514 __ li(a0, Operand(2));
515 __ li(a1, Operand(ExternalReference(IC_Utility(id), isolate)));
516
517 CEntryStub stub(1);
518 __ CallStub(&stub);
519
520 // Move result to a1 and leave the internal frame.
521 __ mov(a1, v0);
522 __ LeaveInternalFrame();
523
524 // Check if the receiver is a global object of some sort.
525 // This can happen only for regular CallIC but not KeyedCallIC.
526 if (id == IC::kCallIC_Miss) {
527 Label invoke, global;
528 __ lw(a2, MemOperand(sp, argc * kPointerSize));
529 __ andi(t0, a2, kSmiTagMask);
530 __ Branch(&invoke, eq, t0, Operand(zero_reg));
531 __ GetObjectType(a2, a3, a3);
532 __ Branch(&global, eq, a3, Operand(JS_GLOBAL_OBJECT_TYPE));
533 __ Branch(&invoke, ne, a3, Operand(JS_BUILTINS_OBJECT_TYPE));
534
535 // Patch the receiver on the stack.
536 __ bind(&global);
537 __ lw(a2, FieldMemOperand(a2, GlobalObject::kGlobalReceiverOffset));
538 __ sw(a2, MemOperand(sp, argc * kPointerSize));
539 __ bind(&invoke);
540 }
541 // Invoke the function.
danno@chromium.org40cb8782011-05-25 07:58:50 +0000542 CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
543 ? CALL_AS_FUNCTION
544 : CALL_AS_METHOD;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000545 ParameterCount actual(argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000546 __ InvokeFunction(a1,
547 actual,
548 JUMP_FUNCTION,
549 NullCallWrapper(),
550 call_kind);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000551}
552
lrn@chromium.org7516f052011-03-30 08:52:27 +0000553
danno@chromium.org40cb8782011-05-25 07:58:50 +0000554void CallIC::GenerateMiss(MacroAssembler* masm,
555 int argc,
556 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000557 // ----------- S t a t e -------------
558 // -- a2 : name
559 // -- ra : return address
560 // -----------------------------------
561
danno@chromium.org40cb8782011-05-25 07:58:50 +0000562 GenerateCallMiss(masm, argc, IC::kCallIC_Miss, extra_ic_state);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000563}
564
565
danno@chromium.org40cb8782011-05-25 07:58:50 +0000566void CallIC::GenerateMegamorphic(MacroAssembler* masm,
567 int argc,
568 Code::ExtraICState extra_ic_state) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000569 // ----------- S t a t e -------------
570 // -- a2 : name
571 // -- ra : return address
572 // -----------------------------------
573
574 // Get the receiver of the function from the stack into a1.
575 __ lw(a1, MemOperand(sp, argc * kPointerSize));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000576 GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
577 GenerateMiss(masm, argc, extra_ic_state);
ager@chromium.org5c838252010-02-19 08:53:10 +0000578}
579
580
581void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000582 // ----------- S t a t e -------------
583 // -- a2 : name
584 // -- ra : return address
585 // -----------------------------------
586
587 GenerateCallNormal(masm, argc);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000588 GenerateMiss(masm, argc, Code::kNoExtraICState);
ager@chromium.org5c838252010-02-19 08:53:10 +0000589}
590
lrn@chromium.org7516f052011-03-30 08:52:27 +0000591
592void KeyedCallIC::GenerateMiss(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000593 // ----------- S t a t e -------------
594 // -- a2 : name
595 // -- ra : return address
596 // -----------------------------------
597
danno@chromium.org40cb8782011-05-25 07:58:50 +0000598 GenerateCallMiss(masm, argc, IC::kKeyedCallIC_Miss, Code::kNoExtraICState);
ager@chromium.org5c838252010-02-19 08:53:10 +0000599}
600
lrn@chromium.org7516f052011-03-30 08:52:27 +0000601
602void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000603 // ----------- S t a t e -------------
604 // -- a2 : name
605 // -- ra : return address
606 // -----------------------------------
607
608 // Get the receiver of the function from the stack into a1.
609 __ lw(a1, MemOperand(sp, argc * kPointerSize));
610
611 Label do_call, slow_call, slow_load, slow_reload_receiver;
612 Label check_number_dictionary, check_string, lookup_monomorphic_cache;
613 Label index_smi, index_string;
614
615 // Check that the key is a smi.
616 __ JumpIfNotSmi(a2, &check_string);
617 __ bind(&index_smi);
618 // Now the key is known to be a smi. This place is also jumped to from below
619 // where a numeric string is converted to a smi.
620
621 GenerateKeyedLoadReceiverCheck(
622 masm, a1, a0, a3, Map::kHasIndexedInterceptor, &slow_call);
623
624 GenerateFastArrayLoad(
625 masm, a1, a2, t0, a3, a0, a1, &check_number_dictionary, &slow_load);
626 Counters* counters = masm->isolate()->counters();
627 __ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, a0, a3);
628
629 __ bind(&do_call);
630 // receiver in a1 is not used after this point.
631 // a2: key
632 // a1: function
633
634 GenerateFunctionTailCall(masm, argc, &slow_call, a0);
635
636 __ bind(&check_number_dictionary);
637 // a2: key
638 // a3: elements map
639 // t0: elements pointer
640 // Check whether the elements is a number dictionary.
641 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
642 __ Branch(&slow_load, ne, a3, Operand(at));
643 __ sra(a0, a2, kSmiTagSize);
644 // a0: untagged index
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000645 __ LoadFromNumberDictionary(&slow_load, t0, a2, a1, a0, a3, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000646 __ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3);
647 __ jmp(&do_call);
648
649 __ bind(&slow_load);
650 // This branch is taken when calling KeyedCallIC_Miss is neither required
651 // nor beneficial.
652 __ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3);
653 __ EnterInternalFrame();
654 __ push(a2); // Save the key.
655 __ Push(a1, a2); // Pass the receiver and the key.
656 __ CallRuntime(Runtime::kKeyedGetProperty, 2);
657 __ pop(a2); // Restore the key.
658 __ LeaveInternalFrame();
659 __ mov(a1, v0);
660 __ jmp(&do_call);
661
662 __ bind(&check_string);
663 GenerateKeyStringCheck(masm, a2, a0, a3, &index_string, &slow_call);
664
665 // The key is known to be a symbol.
666 // If the receiver is a regular JS object with slow properties then do
667 // a quick inline probe of the receiver's dictionary.
668 // Otherwise do the monomorphic cache probe.
669 GenerateKeyedLoadReceiverCheck(
670 masm, a1, a0, a3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
671
672 __ lw(a0, FieldMemOperand(a1, JSObject::kPropertiesOffset));
673 __ lw(a3, FieldMemOperand(a0, HeapObject::kMapOffset));
674 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
675 __ Branch(&lookup_monomorphic_cache, ne, a3, Operand(at));
676
677 GenerateDictionaryLoad(masm, &slow_load, a0, a2, a1, a3, t0);
678 __ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, a0, a3);
679 __ jmp(&do_call);
680
681 __ bind(&lookup_monomorphic_cache);
682 __ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000683 GenerateMonomorphicCacheProbe(masm,
684 argc,
685 Code::KEYED_CALL_IC,
686 Code::kNoExtraICState);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000687 // Fall through on miss.
688
689 __ bind(&slow_call);
690 // This branch is taken if:
691 // - the receiver requires boxing or access check,
692 // - the key is neither smi nor symbol,
693 // - the value loaded is not a function,
694 // - there is hope that the runtime will create a monomorphic call stub,
695 // that will get fetched next time.
696 __ IncrementCounter(counters->keyed_call_generic_slow(), 1, a0, a3);
697 GenerateMiss(masm, argc);
698
699 __ bind(&index_string);
700 __ IndexFromHash(a3, a2);
701 // Now jump to the place where smi keys are handled.
702 __ jmp(&index_smi);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000703}
704
705
706void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000707 // ----------- S t a t e -------------
708 // -- a2 : name
709 // -- ra : return address
710 // -----------------------------------
711
712 // Check if the name is a string.
713 Label miss;
714 __ JumpIfSmi(a2, &miss);
715 __ IsObjectJSStringType(a2, a0, &miss);
716
717 GenerateCallNormal(masm, argc);
718 __ bind(&miss);
719 GenerateMiss(masm, argc);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000720}
721
722
ager@chromium.org5c838252010-02-19 08:53:10 +0000723// Defined in ic.cc.
724Object* LoadIC_Miss(Arguments args);
725
726void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000727 // ----------- S t a t e -------------
728 // -- a2 : name
729 // -- ra : return address
730 // -- a0 : receiver
731 // -- sp[0] : receiver
732 // -----------------------------------
733
734 // Probe the stub cache.
735 Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
736 NOT_IN_LOOP,
737 MONOMORPHIC);
738 Isolate::Current()->stub_cache()->GenerateProbe(
739 masm, flags, a0, a2, a3, t0, t1);
740
741 // Cache miss: Jump to runtime.
742 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +0000743}
744
745
746void LoadIC::GenerateNormal(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000747 // ----------- S t a t e -------------
748 // -- a2 : name
749 // -- lr : return address
750 // -- a0 : receiver
751 // -- sp[0] : receiver
752 // -----------------------------------
753 Label miss;
754
755 GenerateStringDictionaryReceiverCheck(masm, a0, a1, a3, t0, &miss);
756
757 // a1: elements
758 GenerateDictionaryLoad(masm, &miss, a1, a2, v0, a3, t0);
759 __ Ret();
760
761 // Cache miss: Jump to runtime.
762 __ bind(&miss);
763 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +0000764}
765
766
767void LoadIC::GenerateMiss(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000768 // ----------- S t a t e -------------
769 // -- a2 : name
770 // -- ra : return address
771 // -- a0 : receiver
772 // -- sp[0] : receiver
773 // -----------------------------------
774 Isolate* isolate = masm->isolate();
775
776 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
777
778 __ mov(a3, a0);
779 __ Push(a3, a2);
780
781 // Perform tail call to the entry.
782 ExternalReference ref = ExternalReference(IC_Utility(kLoadIC_Miss), isolate);
783 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000784}
785
786
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000787static MemOperand GenerateMappedArgumentsLookup(MacroAssembler* masm,
788 Register object,
789 Register key,
790 Register scratch1,
791 Register scratch2,
792 Register scratch3,
793 Label* unmapped_case,
794 Label* slow_case) {
795 Heap* heap = masm->isolate()->heap();
796
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000797 // Check that the receiver is a JSObject. Because of the map check
798 // later, we do not need to check for interceptors or whether it
799 // requires access checks.
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000800 __ JumpIfSmi(object, slow_case);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000801 // Check that the object is some kind of JSObject.
802 __ GetObjectType(object, scratch1, scratch2);
803 __ Branch(slow_case, lt, scratch2, Operand(FIRST_JS_RECEIVER_TYPE));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000804
805 // Check that the key is a positive smi.
806 __ And(scratch1, key, Operand(0x8000001));
807 __ Branch(slow_case, ne, scratch1, Operand(zero_reg));
808
809 // Load the elements into scratch1 and check its map.
810 Handle<Map> arguments_map(heap->non_strict_arguments_elements_map());
811 __ lw(scratch1, FieldMemOperand(object, JSObject::kElementsOffset));
812 __ CheckMap(scratch1, scratch2, arguments_map, slow_case, DONT_DO_SMI_CHECK);
813
814 // Check if element is in the range of mapped arguments. If not, jump
815 // to the unmapped lookup with the parameter map in scratch1.
816 __ lw(scratch2, FieldMemOperand(scratch1, FixedArray::kLengthOffset));
817 __ Subu(scratch2, scratch2, Operand(Smi::FromInt(2)));
818 __ Branch(unmapped_case, Ugreater_equal, key, Operand(scratch2));
819
820 // Load element index and check whether it is the hole.
821 const int kOffset =
822 FixedArray::kHeaderSize + 2 * kPointerSize - kHeapObjectTag;
823
824 __ li(scratch3, Operand(kPointerSize >> 1));
825 __ mul(scratch3, key, scratch3);
826 __ Addu(scratch3, scratch3, Operand(kOffset));
827
828 __ Addu(scratch2, scratch1, scratch3);
829 __ lw(scratch2, MemOperand(scratch2));
830 __ LoadRoot(scratch3, Heap::kTheHoleValueRootIndex);
831 __ Branch(unmapped_case, eq, scratch2, Operand(scratch3));
832
833 // Load value from context and return it. We can reuse scratch1 because
834 // we do not jump to the unmapped lookup (which requires the parameter
835 // map in scratch1).
836 __ lw(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
837 __ li(scratch3, Operand(kPointerSize >> 1));
838 __ mul(scratch3, scratch2, scratch3);
839 __ Addu(scratch3, scratch3, Operand(Context::kHeaderSize - kHeapObjectTag));
840 __ Addu(scratch2, scratch1, scratch3);
841 return MemOperand(scratch2);
842}
843
844
845static MemOperand GenerateUnmappedArgumentsLookup(MacroAssembler* masm,
846 Register key,
847 Register parameter_map,
848 Register scratch,
849 Label* slow_case) {
850 // Element is in arguments backing store, which is referenced by the
851 // second element of the parameter_map. The parameter_map register
852 // must be loaded with the parameter map of the arguments object and is
853 // overwritten.
854 const int kBackingStoreOffset = FixedArray::kHeaderSize + kPointerSize;
855 Register backing_store = parameter_map;
856 __ lw(backing_store, FieldMemOperand(parameter_map, kBackingStoreOffset));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000857 Handle<Map> fixed_array_map(masm->isolate()->heap()->fixed_array_map());
858 __ CheckMap(backing_store, scratch, fixed_array_map, slow_case,
859 DONT_DO_SMI_CHECK);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000860 __ lw(scratch, FieldMemOperand(backing_store, FixedArray::kLengthOffset));
861 __ Branch(slow_case, Ugreater_equal, key, Operand(scratch));
862 __ li(scratch, Operand(kPointerSize >> 1));
863 __ mul(scratch, key, scratch);
864 __ Addu(scratch,
865 scratch,
866 Operand(FixedArray::kHeaderSize - kHeapObjectTag));
867 __ Addu(scratch, backing_store, scratch);
868 return MemOperand(scratch);
869}
870
871
872void KeyedLoadIC::GenerateNonStrictArguments(MacroAssembler* masm) {
873 // ---------- S t a t e --------------
874 // -- lr : return address
875 // -- a0 : key
876 // -- a1 : receiver
877 // -----------------------------------
878 Label slow, notin;
879 MemOperand mapped_location =
880 GenerateMappedArgumentsLookup(masm, a1, a0, a2, a3, t0, &notin, &slow);
881 __ lw(v0, mapped_location);
882 __ Ret();
883 __ bind(&notin);
884 // The unmapped lookup expects that the parameter map is in a2.
885 MemOperand unmapped_location =
886 GenerateUnmappedArgumentsLookup(masm, a0, a2, a3, &slow);
887 __ lw(a2, unmapped_location);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000888 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000889 __ Branch(&slow, eq, a2, Operand(a3));
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000890 __ mov(v0, a2);
891 __ Ret();
892 __ bind(&slow);
893 GenerateMiss(masm, false);
894}
895
896
897void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
898 // ---------- S t a t e --------------
899 // -- a0 : value
900 // -- a1 : key
901 // -- a2 : receiver
902 // -- lr : return address
903 // -----------------------------------
904 Label slow, notin;
905 MemOperand mapped_location =
906 GenerateMappedArgumentsLookup(masm, a2, a1, a3, t0, t1, &notin, &slow);
907 __ sw(a0, mapped_location);
ager@chromium.org04921a82011-06-27 13:21:41 +0000908 // Verify mapped_location MemOperand is register, with no offset.
909 ASSERT_EQ(mapped_location.offset(), 0);
910 __ RecordWrite(a3, mapped_location.rm(), t5);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000911 __ Ret(USE_DELAY_SLOT);
912 __ mov(v0, a0); // (In delay slot) return the value stored in v0.
913 __ bind(&notin);
914 // The unmapped lookup expects that the parameter map is in a3.
915 MemOperand unmapped_location =
916 GenerateUnmappedArgumentsLookup(masm, a1, a3, t0, &slow);
917 __ sw(a0, unmapped_location);
ager@chromium.org04921a82011-06-27 13:21:41 +0000918 ASSERT_EQ(unmapped_location.offset(), 0);
919 __ RecordWrite(a3, unmapped_location.rm(), t5);
lrn@chromium.orgac2828d2011-06-23 06:29:21 +0000920 __ Ret(USE_DELAY_SLOT);
921 __ mov(v0, a0); // (In delay slot) return the value stored in v0.
922 __ bind(&slow);
923 GenerateMiss(masm, false);
924}
925
926
927void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
928 int argc) {
929 // ----------- S t a t e -------------
930 // -- a2 : name
931 // -- lr : return address
932 // -----------------------------------
933 Label slow, notin;
934 // Load receiver.
935 __ lw(a1, MemOperand(sp, argc * kPointerSize));
936 MemOperand mapped_location =
937 GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, &notin, &slow);
938 __ lw(a1, mapped_location);
939 GenerateFunctionTailCall(masm, argc, &slow, a3);
940 __ bind(&notin);
941 // The unmapped lookup expects that the parameter map is in a3.
942 MemOperand unmapped_location =
943 GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow);
944 __ lw(a1, unmapped_location);
945 __ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
946 __ Branch(&slow, eq, a1, Operand(a3));
947 GenerateFunctionTailCall(masm, argc, &slow, a3);
948 __ bind(&slow);
949 GenerateMiss(masm, argc);
950}
951
952
953Object* KeyedLoadIC_Miss(Arguments args);
954
955
danno@chromium.org40cb8782011-05-25 07:58:50 +0000956void KeyedLoadIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000957 // ---------- S t a t e --------------
958 // -- ra : return address
959 // -- a0 : key
960 // -- a1 : receiver
961 // -----------------------------------
962 Isolate* isolate = masm->isolate();
963
964 __ IncrementCounter(isolate->counters()->keyed_load_miss(), 1, a3, t0);
965
966 __ Push(a1, a0);
967
danno@chromium.org40cb8782011-05-25 07:58:50 +0000968 // Perform tail call to the entry.
969 ExternalReference ref = force_generic
970 ? ExternalReference(IC_Utility(kKeyedLoadIC_MissForceGeneric), isolate)
971 : ExternalReference(IC_Utility(kKeyedLoadIC_Miss), isolate);
972
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000973 __ TailCallExternalReference(ref, 2, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +0000974}
975
976
lrn@chromium.org7516f052011-03-30 08:52:27 +0000977void KeyedLoadIC::GenerateRuntimeGetProperty(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000978 // ---------- S t a t e --------------
979 // -- ra : return address
980 // -- a0 : key
981 // -- a1 : receiver
982 // -----------------------------------
983
984 __ Push(a1, a0);
985
986 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000987}
988
989
ager@chromium.org5c838252010-02-19 08:53:10 +0000990void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000991 // ---------- S t a t e --------------
992 // -- ra : return address
993 // -- a0 : key
994 // -- a1 : receiver
995 // -----------------------------------
996 Label slow, check_string, index_smi, index_string, property_array_property;
997 Label probe_dictionary, check_number_dictionary;
998
999 Register key = a0;
1000 Register receiver = a1;
1001
1002 Isolate* isolate = masm->isolate();
1003
1004 // Check that the key is a smi.
1005 __ JumpIfNotSmi(key, &check_string);
1006 __ bind(&index_smi);
1007 // Now the key is known to be a smi. This place is also jumped to from below
1008 // where a numeric string is converted to a smi.
1009
1010 GenerateKeyedLoadReceiverCheck(
1011 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
1012
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001013 // Check the receiver's map to see if it has fast elements.
1014 __ CheckFastElements(a2, a3, &check_number_dictionary);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001015
1016 GenerateFastArrayLoad(
1017 masm, receiver, key, t0, a3, a2, v0, NULL, &slow);
1018
1019 __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, a2, a3);
1020 __ Ret();
1021
1022 __ bind(&check_number_dictionary);
1023 __ lw(t0, FieldMemOperand(receiver, JSObject::kElementsOffset));
1024 __ lw(a3, FieldMemOperand(t0, JSObject::kMapOffset));
1025
1026 // Check whether the elements is a number dictionary.
1027 // a0: key
1028 // a3: elements map
1029 // t0: elements
1030 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
1031 __ Branch(&slow, ne, a3, Operand(at));
1032 __ sra(a2, a0, kSmiTagSize);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001033 __ LoadFromNumberDictionary(&slow, t0, a0, v0, a2, a3, t1);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001034 __ Ret();
1035
1036 // Slow case, key and receiver still in a0 and a1.
1037 __ bind(&slow);
1038 __ IncrementCounter(isolate->counters()->keyed_load_generic_slow(),
1039 1,
1040 a2,
1041 a3);
1042 GenerateRuntimeGetProperty(masm);
1043
1044 __ bind(&check_string);
1045 GenerateKeyStringCheck(masm, key, a2, a3, &index_string, &slow);
1046
1047 GenerateKeyedLoadReceiverCheck(
1048 masm, receiver, a2, a3, Map::kHasIndexedInterceptor, &slow);
1049
1050
1051 // If the receiver is a fast-case object, check the keyed lookup
1052 // cache. Otherwise probe the dictionary.
1053 __ lw(a3, FieldMemOperand(a1, JSObject::kPropertiesOffset));
1054 __ lw(t0, FieldMemOperand(a3, HeapObject::kMapOffset));
1055 __ LoadRoot(at, Heap::kHashTableMapRootIndex);
1056 __ Branch(&probe_dictionary, eq, t0, Operand(at));
1057
1058 // Load the map of the receiver, compute the keyed lookup cache hash
1059 // based on 32 bits of the map pointer and the string hash.
1060 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1061 __ sra(a3, a2, KeyedLookupCache::kMapHashShift);
1062 __ lw(t0, FieldMemOperand(a0, String::kHashFieldOffset));
1063 __ sra(at, t0, String::kHashShift);
1064 __ xor_(a3, a3, at);
1065 __ And(a3, a3, Operand(KeyedLookupCache::kCapacityMask));
1066
1067 // Load the key (consisting of map and symbol) from the cache and
1068 // check for match.
1069 ExternalReference cache_keys =
1070 ExternalReference::keyed_lookup_cache_keys(isolate);
1071 __ li(t0, Operand(cache_keys));
1072 __ sll(at, a3, kPointerSizeLog2 + 1);
1073 __ addu(t0, t0, at);
1074 __ lw(t1, MemOperand(t0)); // Move t0 to symbol.
1075 __ Addu(t0, t0, Operand(kPointerSize));
1076 __ Branch(&slow, ne, a2, Operand(t1));
1077 __ lw(t1, MemOperand(t0));
1078 __ Branch(&slow, ne, a0, Operand(t1));
1079
1080 // Get field offset.
1081 // a0 : key
1082 // a1 : receiver
1083 // a2 : receiver's map
1084 // a3 : lookup cache index
1085 ExternalReference cache_field_offsets =
1086 ExternalReference::keyed_lookup_cache_field_offsets(isolate);
1087 __ li(t0, Operand(cache_field_offsets));
1088 __ sll(at, a3, kPointerSizeLog2);
1089 __ addu(at, t0, at);
1090 __ lw(t1, MemOperand(at));
1091 __ lbu(t2, FieldMemOperand(a2, Map::kInObjectPropertiesOffset));
1092 __ Subu(t1, t1, t2);
1093 __ Branch(&property_array_property, ge, t1, Operand(zero_reg));
1094
1095 // Load in-object property.
1096 __ lbu(t2, FieldMemOperand(a2, Map::kInstanceSizeOffset));
1097 __ addu(t2, t2, t1); // Index from start of object.
1098 __ Subu(a1, a1, Operand(kHeapObjectTag)); // Remove the heap tag.
1099 __ sll(at, t2, kPointerSizeLog2);
1100 __ addu(at, a1, at);
1101 __ lw(v0, MemOperand(at));
1102 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1103 1,
1104 a2,
1105 a3);
1106 __ Ret();
1107
1108 // Load property array property.
1109 __ bind(&property_array_property);
1110 __ lw(a1, FieldMemOperand(a1, JSObject::kPropertiesOffset));
1111 __ Addu(a1, a1, FixedArray::kHeaderSize - kHeapObjectTag);
1112 __ sll(t0, t1, kPointerSizeLog2);
1113 __ Addu(t0, t0, a1);
1114 __ lw(v0, MemOperand(t0));
1115 __ IncrementCounter(isolate->counters()->keyed_load_generic_lookup_cache(),
1116 1,
1117 a2,
1118 a3);
1119 __ Ret();
1120
1121
1122 // Do a quick inline probe of the receiver's dictionary, if it
1123 // exists.
1124 __ bind(&probe_dictionary);
1125 // a1: receiver
1126 // a0: key
1127 // a3: elements
1128 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1129 __ lbu(a2, FieldMemOperand(a2, Map::kInstanceTypeOffset));
1130 GenerateGlobalInstanceTypeCheck(masm, a2, &slow);
1131 // Load the property to v0.
1132 GenerateDictionaryLoad(masm, &slow, a3, a0, v0, a2, t0);
1133 __ IncrementCounter(isolate->counters()->keyed_load_generic_symbol(),
1134 1,
1135 a2,
1136 a3);
1137 __ Ret();
1138
1139 __ bind(&index_string);
1140 __ IndexFromHash(a3, key);
1141 // Now jump to the place where smi keys are handled.
1142 __ Branch(&index_smi);
ager@chromium.org5c838252010-02-19 08:53:10 +00001143}
1144
1145
1146void KeyedLoadIC::GenerateString(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001147 // ---------- S t a t e --------------
1148 // -- ra : return address
1149 // -- a0 : key (index)
1150 // -- a1 : receiver
1151 // -----------------------------------
1152 Label miss;
1153
1154 Register receiver = a1;
1155 Register index = a0;
1156 Register scratch1 = a2;
1157 Register scratch2 = a3;
1158 Register result = v0;
1159
1160 StringCharAtGenerator char_at_generator(receiver,
1161 index,
1162 scratch1,
1163 scratch2,
1164 result,
1165 &miss, // When not a string.
1166 &miss, // When not a number.
1167 &miss, // When index out of range.
1168 STRING_INDEX_IS_ARRAY_INDEX);
1169 char_at_generator.GenerateFast(masm);
1170 __ Ret();
1171
1172 StubRuntimeCallHelper call_helper;
1173 char_at_generator.GenerateSlow(masm, call_helper);
1174
1175 __ bind(&miss);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001176 GenerateMiss(masm, false);
ager@chromium.org5c838252010-02-19 08:53:10 +00001177}
1178
1179
lrn@chromium.org7516f052011-03-30 08:52:27 +00001180void KeyedStoreIC::GenerateRuntimeSetProperty(MacroAssembler* masm,
1181 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001182 // ---------- S t a t e --------------
1183 // -- a0 : value
1184 // -- a1 : key
1185 // -- a2 : receiver
1186 // -- ra : return address
1187 // -----------------------------------
1188
1189 // Push receiver, key and value for runtime call.
1190 __ Push(a2, a1, a0);
1191 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1192 __ li(a0, Operand(Smi::FromInt(strict_mode))); // Strict mode.
1193 __ Push(a1, a0);
1194
1195 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001196}
1197
1198
1199void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm,
1200 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001201 // ---------- S t a t e --------------
1202 // -- a0 : value
1203 // -- a1 : key
1204 // -- a2 : receiver
1205 // -- ra : return address
1206 // -----------------------------------
1207
1208 Label slow, fast, array, extra, exit;
1209
1210 // Register usage.
1211 Register value = a0;
1212 Register key = a1;
1213 Register receiver = a2;
1214 Register elements = a3; // Elements array of the receiver.
1215 // t0 is used as ip in the arm version.
1216 // t3-t4 are used as temporaries.
1217
1218 // Check that the key is a smi.
1219 __ JumpIfNotSmi(key, &slow);
1220 // Check that the object isn't a smi.
1221 __ JumpIfSmi(receiver, &slow);
1222
1223 // Get the map of the object.
1224 __ lw(t3, FieldMemOperand(receiver, HeapObject::kMapOffset));
1225 // Check that the receiver does not require access checks. We need
1226 // to do this because this generic stub does not perform map checks.
1227 __ lbu(t0, FieldMemOperand(t3, Map::kBitFieldOffset));
1228 __ And(t0, t0, Operand(1 << Map::kIsAccessCheckNeeded));
1229 __ Branch(&slow, ne, t0, Operand(zero_reg));
1230 // Check if the object is a JS array or not.
1231 __ lbu(t3, FieldMemOperand(t3, Map::kInstanceTypeOffset));
1232
1233 __ Branch(&array, eq, t3, Operand(JS_ARRAY_TYPE));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001234 // Check that the object is some kind of JSObject.
1235 __ Branch(&slow, lt, t3, Operand(FIRST_JS_RECEIVER_TYPE));
1236 __ Branch(&slow, eq, t3, Operand(JS_PROXY_TYPE));
1237 __ Branch(&slow, eq, t3, Operand(JS_FUNCTION_PROXY_TYPE));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001238
1239 // Object case: Check key against length in the elements array.
1240 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1241 // Check that the object is in fast mode and writable.
1242 __ lw(t3, FieldMemOperand(elements, HeapObject::kMapOffset));
1243 __ LoadRoot(t0, Heap::kFixedArrayMapRootIndex);
1244 __ Branch(&slow, ne, t3, Operand(t0));
1245 // Check array bounds. Both the key and the length of FixedArray are smis.
1246 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1247 __ Branch(&fast, lo, key, Operand(t0));
1248 // Fall thru to slow if un-tagged index >= length.
1249
1250 // Slow case, handle jump to runtime.
1251 __ bind(&slow);
1252
1253 // Entry registers are intact.
1254 // a0: value.
1255 // a1: key.
1256 // a2: receiver.
1257
1258 GenerateRuntimeSetProperty(masm, strict_mode);
1259
1260 // Extra capacity case: Check if there is extra capacity to
1261 // perform the store and update the length. Used for adding one
1262 // element to the array by writing to array[array.length].
1263
1264 __ bind(&extra);
1265 // Only support writing to array[array.length].
1266 __ Branch(&slow, ne, key, Operand(t0));
1267 // Check for room in the elements backing store.
1268 // Both the key and the length of FixedArray are smis.
1269 __ lw(t0, FieldMemOperand(elements, FixedArray::kLengthOffset));
1270 __ Branch(&slow, hs, key, Operand(t0));
1271 // Calculate key + 1 as smi.
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001272 STATIC_ASSERT(0 == kSmiTag);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001273 __ Addu(t3, key, Operand(Smi::FromInt(1)));
1274 __ sw(t3, FieldMemOperand(receiver, JSArray::kLengthOffset));
1275 __ Branch(&fast);
1276
1277
1278 // Array case: Get the length and the elements array from the JS
1279 // array. Check that the array is in fast mode (and writable); if it
1280 // is the length is always a smi.
1281
1282 __ bind(&array);
1283 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
1284 __ lw(t3, FieldMemOperand(elements, HeapObject::kMapOffset));
1285 __ LoadRoot(t0, Heap::kFixedArrayMapRootIndex);
1286 __ Branch(&slow, ne, t3, Operand(t0));
1287
1288 // Check the key against the length in the array.
1289 __ lw(t0, FieldMemOperand(receiver, JSArray::kLengthOffset));
1290 __ Branch(&extra, hs, key, Operand(t0));
1291 // Fall through to fast case.
1292
1293 __ bind(&fast);
1294 // Fast case, store the value to the elements backing store.
1295 __ Addu(t4, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1296 __ sll(t1, key, kPointerSizeLog2 - kSmiTagSize);
1297 __ Addu(t4, t4, Operand(t1));
1298 __ sw(value, MemOperand(t4));
1299 // Skip write barrier if the written value is a smi.
1300 __ JumpIfSmi(value, &exit);
1301
1302 // Update write barrier for the elements array address.
1303 __ Subu(t3, t4, Operand(elements));
1304
1305 __ RecordWrite(elements, Operand(t3), t4, t5);
1306 __ bind(&exit);
1307
1308 __ mov(v0, a0); // Return the value written.
1309 __ Ret();
ager@chromium.org5c838252010-02-19 08:53:10 +00001310}
1311
1312
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001313void KeyedLoadIC::GenerateIndexedInterceptor(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001314 // ---------- S t a t e --------------
1315 // -- ra : return address
1316 // -- a0 : key
1317 // -- a1 : receiver
1318 // -----------------------------------
1319 Label slow;
1320
1321 // Check that the receiver isn't a smi.
1322 __ JumpIfSmi(a1, &slow);
1323
1324 // Check that the key is an array index, that is Uint32.
1325 __ And(t0, a0, Operand(kSmiTagMask | kSmiSignMask));
1326 __ Branch(&slow, ne, t0, Operand(zero_reg));
1327
1328 // Get the map of the receiver.
1329 __ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
1330
1331 // Check that it has indexed interceptor and access checks
1332 // are not enabled for this object.
1333 __ lbu(a3, FieldMemOperand(a2, Map::kBitFieldOffset));
1334 __ And(a3, a3, Operand(kSlowCaseBitFieldMask));
1335 __ Branch(&slow, ne, a3, Operand(1 << Map::kHasIndexedInterceptor));
1336 // Everything is fine, call runtime.
1337 __ Push(a1, a0); // Receiver, key.
1338
1339 // Perform tail call to the entry.
1340 __ TailCallExternalReference(ExternalReference(
1341 IC_Utility(kKeyedLoadPropertyWithInterceptor), masm->isolate()), 2, 1);
1342
1343 __ bind(&slow);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001344 GenerateMiss(masm, false);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001345}
1346
1347
danno@chromium.org40cb8782011-05-25 07:58:50 +00001348void KeyedStoreIC::GenerateMiss(MacroAssembler* masm, bool force_generic) {
1349 // ---------- S t a t e --------------
1350 // -- a0 : value
1351 // -- a1 : key
1352 // -- a2 : receiver
1353 // -- ra : return address
1354 // -----------------------------------
1355
1356 // Push receiver, key and value for runtime call.
1357 __ Push(a2, a1, a0);
1358
1359 ExternalReference ref = force_generic
1360 ? ExternalReference(IC_Utility(kKeyedStoreIC_MissForceGeneric),
1361 masm->isolate())
1362 : ExternalReference(IC_Utility(kKeyedStoreIC_Miss), masm->isolate());
1363 __ TailCallExternalReference(ref, 3, 1);
1364}
1365
1366
1367void KeyedStoreIC::GenerateSlow(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001368 // ---------- S t a t e --------------
1369 // -- a0 : value
1370 // -- a1 : key
1371 // -- a2 : receiver
1372 // -- ra : return address
1373 // -----------------------------------
1374
1375 // Push receiver, key and value for runtime call.
1376 // We can't use MultiPush as the order of the registers is important.
1377 __ Push(a2, a1, a0);
1378
danno@chromium.org40cb8782011-05-25 07:58:50 +00001379 // The slow case calls into the runtime to complete the store without causing
1380 // an IC miss that would otherwise cause a transition to the generic stub.
1381 ExternalReference ref =
1382 ExternalReference(IC_Utility(kKeyedStoreIC_Slow), masm->isolate());
1383
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001384 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001385}
1386
1387
lrn@chromium.org7516f052011-03-30 08:52:27 +00001388void StoreIC::GenerateMegamorphic(MacroAssembler* masm,
1389 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001390 // ----------- S t a t e -------------
1391 // -- a0 : value
1392 // -- a1 : receiver
1393 // -- a2 : name
1394 // -- ra : return address
1395 // -----------------------------------
1396
1397 // Get the receiver from the stack and probe the stub cache.
1398 Code::Flags flags = Code::ComputeFlags(Code::STORE_IC,
1399 NOT_IN_LOOP,
1400 MONOMORPHIC,
1401 strict_mode);
1402 Isolate::Current()->stub_cache()->GenerateProbe(
1403 masm, flags, a1, a2, a3, t0, t1);
1404
1405 // Cache miss: Jump to runtime.
1406 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +00001407}
1408
1409
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001410void StoreIC::GenerateMiss(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001411 // ----------- S t a t e -------------
1412 // -- a0 : value
1413 // -- a1 : receiver
1414 // -- a2 : name
1415 // -- ra : return address
1416 // -----------------------------------
1417
1418 __ Push(a1, a2, a0);
1419 // Perform tail call to the entry.
1420 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_Miss),
1421 masm->isolate());
1422 __ TailCallExternalReference(ref, 3, 1);
ager@chromium.org5c838252010-02-19 08:53:10 +00001423}
1424
1425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001426void StoreIC::GenerateArrayLength(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001427 // ----------- S t a t e -------------
1428 // -- a0 : value
1429 // -- a1 : receiver
1430 // -- a2 : name
1431 // -- ra : return address
1432 // -----------------------------------
1433 //
1434 // This accepts as a receiver anything JSObject::SetElementsLength accepts
1435 // (currently anything except for external and pixel arrays which means
1436 // anything with elements of FixedArray type.), but currently is restricted
1437 // to JSArray.
1438 // Value must be a number, but only smis are accepted as the most common case.
1439
1440 Label miss;
1441
1442 Register receiver = a1;
1443 Register value = a0;
1444 Register scratch = a3;
1445
1446 // Check that the receiver isn't a smi.
1447 __ JumpIfSmi(receiver, &miss);
1448
1449 // Check that the object is a JS array.
1450 __ GetObjectType(receiver, scratch, scratch);
1451 __ Branch(&miss, ne, scratch, Operand(JS_ARRAY_TYPE));
1452
1453 // Check that elements are FixedArray.
1454 // We rely on StoreIC_ArrayLength below to deal with all types of
1455 // fast elements (including COW).
1456 __ lw(scratch, FieldMemOperand(receiver, JSArray::kElementsOffset));
1457 __ GetObjectType(scratch, scratch, scratch);
1458 __ Branch(&miss, ne, scratch, Operand(FIXED_ARRAY_TYPE));
1459
1460 // Check that value is a smi.
1461 __ JumpIfNotSmi(value, &miss);
1462
1463 // Prepare tail call to StoreIC_ArrayLength.
1464 __ Push(receiver, value);
1465
1466 ExternalReference ref = ExternalReference(IC_Utility(kStoreIC_ArrayLength),
1467 masm->isolate());
1468 __ TailCallExternalReference(ref, 2, 1);
1469
1470 __ bind(&miss);
1471
1472 GenerateMiss(masm);
ager@chromium.org5c838252010-02-19 08:53:10 +00001473}
1474
lrn@chromium.org7516f052011-03-30 08:52:27 +00001475
1476void StoreIC::GenerateNormal(MacroAssembler* masm) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001477 // ----------- S t a t e -------------
1478 // -- a0 : value
1479 // -- a1 : receiver
1480 // -- a2 : name
1481 // -- ra : return address
1482 // -----------------------------------
1483 Label miss;
1484
1485 GenerateStringDictionaryReceiverCheck(masm, a1, a3, t0, t1, &miss);
1486
1487 GenerateDictionaryStore(masm, &miss, a3, a2, a0, t0, t1);
1488 Counters* counters = masm->isolate()->counters();
1489 __ IncrementCounter(counters->store_normal_hit(), 1, t0, t1);
1490 __ Ret();
1491
1492 __ bind(&miss);
1493 __ IncrementCounter(counters->store_normal_miss(), 1, t0, t1);
1494 GenerateMiss(masm);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001495}
1496
1497
1498void StoreIC::GenerateGlobalProxy(MacroAssembler* masm,
1499 StrictModeFlag strict_mode) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001500 // ----------- S t a t e -------------
1501 // -- a0 : value
1502 // -- a1 : receiver
1503 // -- a2 : name
1504 // -- ra : return address
1505 // -----------------------------------
1506
1507 __ Push(a1, a2, a0);
1508
1509 __ li(a1, Operand(Smi::FromInt(NONE))); // PropertyAttributes.
1510 __ li(a0, Operand(Smi::FromInt(strict_mode)));
1511 __ Push(a1, a0);
1512
1513 // Do tail-call to runtime routine.
1514 __ TailCallRuntime(Runtime::kSetProperty, 5, 1);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001515}
1516
1517
ager@chromium.org5c838252010-02-19 08:53:10 +00001518#undef __
1519
lrn@chromium.org7516f052011-03-30 08:52:27 +00001520
1521Condition CompareIC::ComputeCondition(Token::Value op) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001522 switch (op) {
1523 case Token::EQ_STRICT:
1524 case Token::EQ:
1525 return eq;
1526 case Token::LT:
1527 return lt;
1528 case Token::GT:
1529 // Reverse left and right operands to obtain ECMA-262 conversion order.
1530 return lt;
1531 case Token::LTE:
1532 // Reverse left and right operands to obtain ECMA-262 conversion order.
1533 return ge;
1534 case Token::GTE:
1535 return ge;
1536 default:
1537 UNREACHABLE();
1538 return kNoCondition;
1539 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001540}
1541
1542
1543void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001544 HandleScope scope;
1545 Handle<Code> rewritten;
1546 State previous_state = GetState();
1547 State state = TargetState(previous_state, false, x, y);
1548 if (state == GENERIC) {
1549 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS, a1, a0);
1550 rewritten = stub.GetCode();
1551 } else {
1552 ICCompareStub stub(op_, state);
1553 rewritten = stub.GetCode();
1554 }
1555 set_target(*rewritten);
1556
1557#ifdef DEBUG
1558 if (FLAG_trace_ic) {
1559 PrintF("[CompareIC (%s->%s)#%s]\n",
1560 GetStateName(previous_state),
1561 GetStateName(state),
1562 Token::Name(op_));
1563 }
1564#endif
1565
1566 // Activate inlined smi code.
1567 if (previous_state == UNINITIALIZED) {
1568 PatchInlinedSmiCode(address());
1569 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001570}
1571
1572
1573void PatchInlinedSmiCode(Address address) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001574 Address andi_instruction_address =
1575 address + Assembler::kCallTargetAddressOffset;
1576
1577 // If the instruction following the call is not a andi at, rx, #yyy, nothing
1578 // was inlined.
1579 Instr instr = Assembler::instr_at(andi_instruction_address);
1580 if (!Assembler::IsAndImmediate(instr)) {
1581 return;
1582 }
1583
1584 // The delta to the start of the map check instruction and the
1585 // condition code uses at the patched jump.
1586 int delta = Assembler::GetImmediate16(instr);
1587 delta += Assembler::GetRs(instr) * kImm16Mask;
1588 // If the delta is 0 the instruction is andi at, zero_reg, #0 which also
1589 // signals that nothing was inlined.
1590 if (delta == 0) {
1591 return;
1592 }
1593
1594#ifdef DEBUG
1595 if (FLAG_trace_ic) {
1596 PrintF("[ patching ic at %p, andi=%p, delta=%d\n",
1597 address, andi_instruction_address, delta);
1598 }
1599#endif
1600
1601 Address patch_address =
1602 andi_instruction_address - delta * Instruction::kInstrSize;
1603 Instr instr_at_patch = Assembler::instr_at(patch_address);
1604 Instr branch_instr =
1605 Assembler::instr_at(patch_address + Instruction::kInstrSize);
1606 ASSERT(Assembler::IsAndImmediate(instr_at_patch));
1607 ASSERT_EQ(0, Assembler::GetImmediate16(instr_at_patch));
1608 ASSERT(Assembler::IsBranch(branch_instr));
1609 if (Assembler::IsBeq(branch_instr)) {
1610 // This is patching a "jump if not smi" site to be active.
1611 // Changing:
1612 // andi at, rx, 0
1613 // Branch <target>, eq, at, Operand(zero_reg)
1614 // to:
1615 // andi at, rx, #kSmiTagMask
1616 // Branch <target>, ne, at, Operand(zero_reg)
1617 CodePatcher patcher(patch_address, 2);
1618 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
1619 patcher.masm()->andi(at, reg, kSmiTagMask);
1620 patcher.ChangeBranchCondition(ne);
1621 } else {
1622 ASSERT(Assembler::IsBne(branch_instr));
1623 // This is patching a "jump if smi" site to be active.
1624 // Changing:
1625 // andi at, rx, 0
1626 // Branch <target>, ne, at, Operand(zero_reg)
1627 // to:
1628 // andi at, rx, #kSmiTagMask
1629 // Branch <target>, eq, at, Operand(zero_reg)
1630 CodePatcher patcher(patch_address, 2);
1631 Register reg = Register::from_code(Assembler::GetRs(instr_at_patch));
1632 patcher.masm()->andi(at, reg, kSmiTagMask);
1633 patcher.ChangeBranchCondition(eq);
1634 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001635}
1636
1637
ager@chromium.org5c838252010-02-19 08:53:10 +00001638} } // namespace v8::internal
1639
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001640#endif // V8_TARGET_ARCH_MIPS