blob: 12d81bca2a98fe413c71e8929e48a00b4d843e19 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <limits.h> // For LONG_MIN, LONG_MAX.
6
7#include "src/v8.h"
8
9#if V8_TARGET_ARCH_MIPS64
10
11#include "src/base/division-by-constant.h"
12#include "src/bootstrapper.h"
13#include "src/codegen.h"
14#include "src/cpu-profiler.h"
15#include "src/debug.h"
16#include "src/isolate-inl.h"
17#include "src/runtime.h"
18
19namespace v8 {
20namespace internal {
21
22MacroAssembler::MacroAssembler(Isolate* arg_isolate, void* buffer, int size)
23 : Assembler(arg_isolate, buffer, size),
24 generating_stub_(false),
25 has_frame_(false) {
26 if (isolate() != NULL) {
27 code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
28 isolate());
29 }
30}
31
32
33void MacroAssembler::Load(Register dst,
34 const MemOperand& src,
35 Representation r) {
36 DCHECK(!r.IsDouble());
37 if (r.IsInteger8()) {
38 lb(dst, src);
39 } else if (r.IsUInteger8()) {
40 lbu(dst, src);
41 } else if (r.IsInteger16()) {
42 lh(dst, src);
43 } else if (r.IsUInteger16()) {
44 lhu(dst, src);
45 } else if (r.IsInteger32()) {
46 lw(dst, src);
47 } else {
48 ld(dst, src);
49 }
50}
51
52
53void MacroAssembler::Store(Register src,
54 const MemOperand& dst,
55 Representation r) {
56 DCHECK(!r.IsDouble());
57 if (r.IsInteger8() || r.IsUInteger8()) {
58 sb(src, dst);
59 } else if (r.IsInteger16() || r.IsUInteger16()) {
60 sh(src, dst);
61 } else if (r.IsInteger32()) {
62 sw(src, dst);
63 } else {
64 if (r.IsHeapObject()) {
65 AssertNotSmi(src);
66 } else if (r.IsSmi()) {
67 AssertSmi(src);
68 }
69 sd(src, dst);
70 }
71}
72
73
74void MacroAssembler::LoadRoot(Register destination,
75 Heap::RootListIndex index) {
76 ld(destination, MemOperand(s6, index << kPointerSizeLog2));
77}
78
79
80void MacroAssembler::LoadRoot(Register destination,
81 Heap::RootListIndex index,
82 Condition cond,
83 Register src1, const Operand& src2) {
84 Branch(2, NegateCondition(cond), src1, src2);
85 ld(destination, MemOperand(s6, index << kPointerSizeLog2));
86}
87
88
89void MacroAssembler::StoreRoot(Register source,
90 Heap::RootListIndex index) {
91 sd(source, MemOperand(s6, index << kPointerSizeLog2));
92}
93
94
95void MacroAssembler::StoreRoot(Register source,
96 Heap::RootListIndex index,
97 Condition cond,
98 Register src1, const Operand& src2) {
99 Branch(2, NegateCondition(cond), src1, src2);
100 sd(source, MemOperand(s6, index << kPointerSizeLog2));
101}
102
103
104// Push and pop all registers that can hold pointers.
105void MacroAssembler::PushSafepointRegisters() {
106 // Safepoints expect a block of kNumSafepointRegisters values on the
107 // stack, so adjust the stack for unsaved registers.
108 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
109 DCHECK(num_unsaved >= 0);
110 if (num_unsaved > 0) {
111 Dsubu(sp, sp, Operand(num_unsaved * kPointerSize));
112 }
113 MultiPush(kSafepointSavedRegisters);
114}
115
116
117void MacroAssembler::PopSafepointRegisters() {
118 const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
119 MultiPop(kSafepointSavedRegisters);
120 if (num_unsaved > 0) {
121 Daddu(sp, sp, Operand(num_unsaved * kPointerSize));
122 }
123}
124
125
126void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
127 sd(src, SafepointRegisterSlot(dst));
128}
129
130
131void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
132 ld(dst, SafepointRegisterSlot(src));
133}
134
135
136int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
137 // The registers are pushed starting with the highest encoding,
138 // which means that lowest encodings are closest to the stack pointer.
139 return kSafepointRegisterStackIndexMap[reg_code];
140}
141
142
143MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
144 return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
145}
146
147
148MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
149 UNIMPLEMENTED_MIPS();
150 // General purpose registers are pushed last on the stack.
151 int doubles_size = FPURegister::NumAllocatableRegisters() * kDoubleSize;
152 int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
153 return MemOperand(sp, doubles_size + register_offset);
154}
155
156
157void MacroAssembler::InNewSpace(Register object,
158 Register scratch,
159 Condition cc,
160 Label* branch) {
161 DCHECK(cc == eq || cc == ne);
162 And(scratch, object, Operand(ExternalReference::new_space_mask(isolate())));
163 Branch(branch, cc, scratch,
164 Operand(ExternalReference::new_space_start(isolate())));
165}
166
167
168void MacroAssembler::RecordWriteField(
169 Register object,
170 int offset,
171 Register value,
172 Register dst,
173 RAStatus ra_status,
174 SaveFPRegsMode save_fp,
175 RememberedSetAction remembered_set_action,
176 SmiCheck smi_check,
177 PointersToHereCheck pointers_to_here_check_for_value) {
178 DCHECK(!AreAliased(value, dst, t8, object));
179 // First, check if a write barrier is even needed. The tests below
180 // catch stores of Smis.
181 Label done;
182
183 // Skip barrier if writing a smi.
184 if (smi_check == INLINE_SMI_CHECK) {
185 JumpIfSmi(value, &done);
186 }
187
188 // Although the object register is tagged, the offset is relative to the start
189 // of the object, so so offset must be a multiple of kPointerSize.
190 DCHECK(IsAligned(offset, kPointerSize));
191
192 Daddu(dst, object, Operand(offset - kHeapObjectTag));
193 if (emit_debug_code()) {
194 Label ok;
195 And(t8, dst, Operand((1 << kPointerSizeLog2) - 1));
196 Branch(&ok, eq, t8, Operand(zero_reg));
197 stop("Unaligned cell in write barrier");
198 bind(&ok);
199 }
200
201 RecordWrite(object,
202 dst,
203 value,
204 ra_status,
205 save_fp,
206 remembered_set_action,
207 OMIT_SMI_CHECK,
208 pointers_to_here_check_for_value);
209
210 bind(&done);
211
212 // Clobber clobbered input registers when running with the debug-code flag
213 // turned on to provoke errors.
214 if (emit_debug_code()) {
215 li(value, Operand(bit_cast<int64_t>(kZapValue + 4)));
216 li(dst, Operand(bit_cast<int64_t>(kZapValue + 8)));
217 }
218}
219
220
221// Will clobber 4 registers: object, map, dst, ip. The
222// register 'object' contains a heap object pointer.
223void MacroAssembler::RecordWriteForMap(Register object,
224 Register map,
225 Register dst,
226 RAStatus ra_status,
227 SaveFPRegsMode fp_mode) {
228 if (emit_debug_code()) {
229 DCHECK(!dst.is(at));
230 ld(dst, FieldMemOperand(map, HeapObject::kMapOffset));
231 Check(eq,
232 kWrongAddressOrValuePassedToRecordWrite,
233 dst,
234 Operand(isolate()->factory()->meta_map()));
235 }
236
237 if (!FLAG_incremental_marking) {
238 return;
239 }
240
241 if (emit_debug_code()) {
242 ld(at, FieldMemOperand(object, HeapObject::kMapOffset));
243 Check(eq,
244 kWrongAddressOrValuePassedToRecordWrite,
245 map,
246 Operand(at));
247 }
248
249 Label done;
250
251 // A single check of the map's pages interesting flag suffices, since it is
252 // only set during incremental collection, and then it's also guaranteed that
253 // the from object's page's interesting flag is also set. This optimization
254 // relies on the fact that maps can never be in new space.
255 CheckPageFlag(map,
256 map, // Used as scratch.
257 MemoryChunk::kPointersToHereAreInterestingMask,
258 eq,
259 &done);
260
261 Daddu(dst, object, Operand(HeapObject::kMapOffset - kHeapObjectTag));
262 if (emit_debug_code()) {
263 Label ok;
264 And(at, dst, Operand((1 << kPointerSizeLog2) - 1));
265 Branch(&ok, eq, at, Operand(zero_reg));
266 stop("Unaligned cell in write barrier");
267 bind(&ok);
268 }
269
270 // Record the actual write.
271 if (ra_status == kRAHasNotBeenSaved) {
272 push(ra);
273 }
274 RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
275 fp_mode);
276 CallStub(&stub);
277 if (ra_status == kRAHasNotBeenSaved) {
278 pop(ra);
279 }
280
281 bind(&done);
282
283 // Count number of write barriers in generated code.
284 isolate()->counters()->write_barriers_static()->Increment();
285 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, at, dst);
286
287 // Clobber clobbered registers when running with the debug-code flag
288 // turned on to provoke errors.
289 if (emit_debug_code()) {
290 li(dst, Operand(bit_cast<int64_t>(kZapValue + 12)));
291 li(map, Operand(bit_cast<int64_t>(kZapValue + 16)));
292 }
293}
294
295
296// Will clobber 4 registers: object, address, scratch, ip. The
297// register 'object' contains a heap object pointer. The heap object
298// tag is shifted away.
299void MacroAssembler::RecordWrite(
300 Register object,
301 Register address,
302 Register value,
303 RAStatus ra_status,
304 SaveFPRegsMode fp_mode,
305 RememberedSetAction remembered_set_action,
306 SmiCheck smi_check,
307 PointersToHereCheck pointers_to_here_check_for_value) {
308 DCHECK(!AreAliased(object, address, value, t8));
309 DCHECK(!AreAliased(object, address, value, t9));
310
311 if (emit_debug_code()) {
312 ld(at, MemOperand(address));
313 Assert(
314 eq, kWrongAddressOrValuePassedToRecordWrite, at, Operand(value));
315 }
316
317 if (remembered_set_action == OMIT_REMEMBERED_SET &&
318 !FLAG_incremental_marking) {
319 return;
320 }
321
322 // First, check if a write barrier is even needed. The tests below
323 // catch stores of smis and stores into the young generation.
324 Label done;
325
326 if (smi_check == INLINE_SMI_CHECK) {
327 DCHECK_EQ(0, kSmiTag);
328 JumpIfSmi(value, &done);
329 }
330
331 if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
332 CheckPageFlag(value,
333 value, // Used as scratch.
334 MemoryChunk::kPointersToHereAreInterestingMask,
335 eq,
336 &done);
337 }
338 CheckPageFlag(object,
339 value, // Used as scratch.
340 MemoryChunk::kPointersFromHereAreInterestingMask,
341 eq,
342 &done);
343
344 // Record the actual write.
345 if (ra_status == kRAHasNotBeenSaved) {
346 push(ra);
347 }
348 RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
349 fp_mode);
350 CallStub(&stub);
351 if (ra_status == kRAHasNotBeenSaved) {
352 pop(ra);
353 }
354
355 bind(&done);
356
357 // Count number of write barriers in generated code.
358 isolate()->counters()->write_barriers_static()->Increment();
359 IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, at,
360 value);
361
362 // Clobber clobbered registers when running with the debug-code flag
363 // turned on to provoke errors.
364 if (emit_debug_code()) {
365 li(address, Operand(bit_cast<int64_t>(kZapValue + 12)));
366 li(value, Operand(bit_cast<int64_t>(kZapValue + 16)));
367 }
368}
369
370
371void MacroAssembler::RememberedSetHelper(Register object, // For debug tests.
372 Register address,
373 Register scratch,
374 SaveFPRegsMode fp_mode,
375 RememberedSetFinalAction and_then) {
376 Label done;
377 if (emit_debug_code()) {
378 Label ok;
379 JumpIfNotInNewSpace(object, scratch, &ok);
380 stop("Remembered set pointer is in new space");
381 bind(&ok);
382 }
383 // Load store buffer top.
384 ExternalReference store_buffer =
385 ExternalReference::store_buffer_top(isolate());
386 li(t8, Operand(store_buffer));
387 ld(scratch, MemOperand(t8));
388 // Store pointer to buffer and increment buffer top.
389 sd(address, MemOperand(scratch));
390 Daddu(scratch, scratch, kPointerSize);
391 // Write back new top of buffer.
392 sd(scratch, MemOperand(t8));
393 // Call stub on end of buffer.
394 // Check for end of buffer.
395 And(t8, scratch, Operand(StoreBuffer::kStoreBufferOverflowBit));
396 DCHECK(!scratch.is(t8));
397 if (and_then == kFallThroughAtEnd) {
398 Branch(&done, eq, t8, Operand(zero_reg));
399 } else {
400 DCHECK(and_then == kReturnAtEnd);
401 Ret(eq, t8, Operand(zero_reg));
402 }
403 push(ra);
404 StoreBufferOverflowStub store_buffer_overflow(isolate(), fp_mode);
405 CallStub(&store_buffer_overflow);
406 pop(ra);
407 bind(&done);
408 if (and_then == kReturnAtEnd) {
409 Ret();
410 }
411}
412
413
414// -----------------------------------------------------------------------------
415// Allocation support.
416
417
418void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
419 Register scratch,
420 Label* miss) {
421 Label same_contexts;
422
423 DCHECK(!holder_reg.is(scratch));
424 DCHECK(!holder_reg.is(at));
425 DCHECK(!scratch.is(at));
426
427 // Load current lexical context from the stack frame.
428 ld(scratch, MemOperand(fp, StandardFrameConstants::kContextOffset));
429 // In debug mode, make sure the lexical context is set.
430#ifdef DEBUG
431 Check(ne, kWeShouldNotHaveAnEmptyLexicalContext,
432 scratch, Operand(zero_reg));
433#endif
434
435 // Load the native context of the current context.
436 int offset =
437 Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
438 ld(scratch, FieldMemOperand(scratch, offset));
439 ld(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
440
441 // Check the context is a native context.
442 if (emit_debug_code()) {
443 push(holder_reg); // Temporarily save holder on the stack.
444 // Read the first word and compare to the native_context_map.
445 ld(holder_reg, FieldMemOperand(scratch, HeapObject::kMapOffset));
446 LoadRoot(at, Heap::kNativeContextMapRootIndex);
447 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext,
448 holder_reg, Operand(at));
449 pop(holder_reg); // Restore holder.
450 }
451
452 // Check if both contexts are the same.
453 ld(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
454 Branch(&same_contexts, eq, scratch, Operand(at));
455
456 // Check the context is a native context.
457 if (emit_debug_code()) {
458 push(holder_reg); // Temporarily save holder on the stack.
459 mov(holder_reg, at); // Move at to its holding place.
460 LoadRoot(at, Heap::kNullValueRootIndex);
461 Check(ne, kJSGlobalProxyContextShouldNotBeNull,
462 holder_reg, Operand(at));
463
464 ld(holder_reg, FieldMemOperand(holder_reg, HeapObject::kMapOffset));
465 LoadRoot(at, Heap::kNativeContextMapRootIndex);
466 Check(eq, kJSGlobalObjectNativeContextShouldBeANativeContext,
467 holder_reg, Operand(at));
468 // Restore at is not needed. at is reloaded below.
469 pop(holder_reg); // Restore holder.
470 // Restore at to holder's context.
471 ld(at, FieldMemOperand(holder_reg, JSGlobalProxy::kNativeContextOffset));
472 }
473
474 // Check that the security token in the calling global object is
475 // compatible with the security token in the receiving global
476 // object.
477 int token_offset = Context::kHeaderSize +
478 Context::SECURITY_TOKEN_INDEX * kPointerSize;
479
480 ld(scratch, FieldMemOperand(scratch, token_offset));
481 ld(at, FieldMemOperand(at, token_offset));
482 Branch(miss, ne, scratch, Operand(at));
483
484 bind(&same_contexts);
485}
486
487
488// Compute the hash code from the untagged key. This must be kept in sync with
489// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
490// code-stub-hydrogen.cc
491void MacroAssembler::GetNumberHash(Register reg0, Register scratch) {
492 // First of all we assign the hash seed to scratch.
493 LoadRoot(scratch, Heap::kHashSeedRootIndex);
494 SmiUntag(scratch);
495
496 // Xor original key with a seed.
497 xor_(reg0, reg0, scratch);
498
499 // Compute the hash code from the untagged key. This must be kept in sync
500 // with ComputeIntegerHash in utils.h.
501 //
502 // hash = ~hash + (hash << 15);
503 // The algorithm uses 32-bit integer values.
504 nor(scratch, reg0, zero_reg);
505 sll(at, reg0, 15);
506 addu(reg0, scratch, at);
507
508 // hash = hash ^ (hash >> 12);
509 srl(at, reg0, 12);
510 xor_(reg0, reg0, at);
511
512 // hash = hash + (hash << 2);
513 sll(at, reg0, 2);
514 addu(reg0, reg0, at);
515
516 // hash = hash ^ (hash >> 4);
517 srl(at, reg0, 4);
518 xor_(reg0, reg0, at);
519
520 // hash = hash * 2057;
521 sll(scratch, reg0, 11);
522 sll(at, reg0, 3);
523 addu(reg0, reg0, at);
524 addu(reg0, reg0, scratch);
525
526 // hash = hash ^ (hash >> 16);
527 srl(at, reg0, 16);
528 xor_(reg0, reg0, at);
529}
530
531
532void MacroAssembler::LoadFromNumberDictionary(Label* miss,
533 Register elements,
534 Register key,
535 Register result,
536 Register reg0,
537 Register reg1,
538 Register reg2) {
539 // Register use:
540 //
541 // elements - holds the slow-case elements of the receiver on entry.
542 // Unchanged unless 'result' is the same register.
543 //
544 // key - holds the smi key on entry.
545 // Unchanged unless 'result' is the same register.
546 //
547 //
548 // result - holds the result on exit if the load succeeded.
549 // Allowed to be the same as 'key' or 'result'.
550 // Unchanged on bailout so 'key' or 'result' can be used
551 // in further computation.
552 //
553 // Scratch registers:
554 //
555 // reg0 - holds the untagged key on entry and holds the hash once computed.
556 //
557 // reg1 - Used to hold the capacity mask of the dictionary.
558 //
559 // reg2 - Used for the index into the dictionary.
560 // at - Temporary (avoid MacroAssembler instructions also using 'at').
561 Label done;
562
563 GetNumberHash(reg0, reg1);
564
565 // Compute the capacity mask.
566 ld(reg1, FieldMemOperand(elements, SeededNumberDictionary::kCapacityOffset));
567 SmiUntag(reg1, reg1);
568 Dsubu(reg1, reg1, Operand(1));
569
570 // Generate an unrolled loop that performs a few probes before giving up.
571 for (int i = 0; i < kNumberDictionaryProbes; i++) {
572 // Use reg2 for index calculations and keep the hash intact in reg0.
573 mov(reg2, reg0);
574 // Compute the masked index: (hash + i + i * i) & mask.
575 if (i > 0) {
576 Daddu(reg2, reg2, Operand(SeededNumberDictionary::GetProbeOffset(i)));
577 }
578 and_(reg2, reg2, reg1);
579
580 // Scale the index by multiplying by the element size.
581 DCHECK(SeededNumberDictionary::kEntrySize == 3);
582 dsll(at, reg2, 1); // 2x.
583 daddu(reg2, reg2, at); // reg2 = reg2 * 3.
584
585 // Check if the key is identical to the name.
586 dsll(at, reg2, kPointerSizeLog2);
587 daddu(reg2, elements, at);
588
589 ld(at, FieldMemOperand(reg2, SeededNumberDictionary::kElementsStartOffset));
590 if (i != kNumberDictionaryProbes - 1) {
591 Branch(&done, eq, key, Operand(at));
592 } else {
593 Branch(miss, ne, key, Operand(at));
594 }
595 }
596
597 bind(&done);
598 // Check that the value is a normal property.
599 // reg2: elements + (index * kPointerSize).
600 const int kDetailsOffset =
601 SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
602 ld(reg1, FieldMemOperand(reg2, kDetailsOffset));
603 And(at, reg1, Operand(Smi::FromInt(PropertyDetails::TypeField::kMask)));
604 Branch(miss, ne, at, Operand(zero_reg));
605
606 // Get the value at the masked, scaled index and return.
607 const int kValueOffset =
608 SeededNumberDictionary::kElementsStartOffset + kPointerSize;
609 ld(result, FieldMemOperand(reg2, kValueOffset));
610}
611
612
613// ---------------------------------------------------------------------------
614// Instruction macros.
615
616void MacroAssembler::Addu(Register rd, Register rs, const Operand& rt) {
617 if (rt.is_reg()) {
618 addu(rd, rs, rt.rm());
619 } else {
620 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
621 addiu(rd, rs, rt.imm64_);
622 } else {
623 // li handles the relocation.
624 DCHECK(!rs.is(at));
625 li(at, rt);
626 addu(rd, rs, at);
627 }
628 }
629}
630
631
632void MacroAssembler::Daddu(Register rd, Register rs, const Operand& rt) {
633 if (rt.is_reg()) {
634 daddu(rd, rs, rt.rm());
635 } else {
636 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
637 daddiu(rd, rs, rt.imm64_);
638 } else {
639 // li handles the relocation.
640 DCHECK(!rs.is(at));
641 li(at, rt);
642 daddu(rd, rs, at);
643 }
644 }
645}
646
647
648void MacroAssembler::Subu(Register rd, Register rs, const Operand& rt) {
649 if (rt.is_reg()) {
650 subu(rd, rs, rt.rm());
651 } else {
652 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
653 addiu(rd, rs, -rt.imm64_); // No subiu instr, use addiu(x, y, -imm).
654 } else {
655 // li handles the relocation.
656 DCHECK(!rs.is(at));
657 li(at, rt);
658 subu(rd, rs, at);
659 }
660 }
661}
662
663
664void MacroAssembler::Dsubu(Register rd, Register rs, const Operand& rt) {
665 if (rt.is_reg()) {
666 dsubu(rd, rs, rt.rm());
667 } else {
668 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
669 daddiu(rd, rs, -rt.imm64_); // No subiu instr, use addiu(x, y, -imm).
670 } else {
671 // li handles the relocation.
672 DCHECK(!rs.is(at));
673 li(at, rt);
674 dsubu(rd, rs, at);
675 }
676 }
677}
678
679
680void MacroAssembler::Mul(Register rd, Register rs, const Operand& rt) {
681 if (rt.is_reg()) {
682 mul(rd, rs, rt.rm());
683 } else {
684 // li handles the relocation.
685 DCHECK(!rs.is(at));
686 li(at, rt);
687 mul(rd, rs, at);
688 }
689}
690
691
692void MacroAssembler::Mulh(Register rd, Register rs, const Operand& rt) {
693 if (rt.is_reg()) {
694 if (kArchVariant != kMips64r6) {
695 mult(rs, rt.rm());
696 mfhi(rd);
697 } else {
698 muh(rd, rs, rt.rm());
699 }
700 } else {
701 // li handles the relocation.
702 DCHECK(!rs.is(at));
703 li(at, rt);
704 if (kArchVariant != kMips64r6) {
705 mult(rs, at);
706 mfhi(rd);
707 } else {
708 muh(rd, rs, at);
709 }
710 }
711}
712
713
714void MacroAssembler::Dmul(Register rd, Register rs, const Operand& rt) {
715 if (rt.is_reg()) {
716 if (kArchVariant == kMips64r6) {
717 dmul(rd, rs, rt.rm());
718 } else {
719 dmult(rs, rt.rm());
720 mflo(rd);
721 }
722 } else {
723 // li handles the relocation.
724 DCHECK(!rs.is(at));
725 li(at, rt);
726 if (kArchVariant == kMips64r6) {
727 dmul(rd, rs, at);
728 } else {
729 dmult(rs, at);
730 mflo(rd);
731 }
732 }
733}
734
735
736void MacroAssembler::Dmulh(Register rd, Register rs, const Operand& rt) {
737 if (rt.is_reg()) {
738 if (kArchVariant == kMips64r6) {
739 dmuh(rd, rs, rt.rm());
740 } else {
741 dmult(rs, rt.rm());
742 mfhi(rd);
743 }
744 } else {
745 // li handles the relocation.
746 DCHECK(!rs.is(at));
747 li(at, rt);
748 if (kArchVariant == kMips64r6) {
749 dmuh(rd, rs, at);
750 } else {
751 dmult(rs, at);
752 mfhi(rd);
753 }
754 }
755}
756
757
758void MacroAssembler::Mult(Register rs, const Operand& rt) {
759 if (rt.is_reg()) {
760 mult(rs, rt.rm());
761 } else {
762 // li handles the relocation.
763 DCHECK(!rs.is(at));
764 li(at, rt);
765 mult(rs, at);
766 }
767}
768
769
770void MacroAssembler::Dmult(Register rs, const Operand& rt) {
771 if (rt.is_reg()) {
772 dmult(rs, rt.rm());
773 } else {
774 // li handles the relocation.
775 DCHECK(!rs.is(at));
776 li(at, rt);
777 dmult(rs, at);
778 }
779}
780
781
782void MacroAssembler::Multu(Register rs, const Operand& rt) {
783 if (rt.is_reg()) {
784 multu(rs, rt.rm());
785 } else {
786 // li handles the relocation.
787 DCHECK(!rs.is(at));
788 li(at, rt);
789 multu(rs, at);
790 }
791}
792
793
794void MacroAssembler::Dmultu(Register rs, const Operand& rt) {
795 if (rt.is_reg()) {
796 dmultu(rs, rt.rm());
797 } else {
798 // li handles the relocation.
799 DCHECK(!rs.is(at));
800 li(at, rt);
801 dmultu(rs, at);
802 }
803}
804
805
806void MacroAssembler::Div(Register rs, const Operand& rt) {
807 if (rt.is_reg()) {
808 div(rs, rt.rm());
809 } else {
810 // li handles the relocation.
811 DCHECK(!rs.is(at));
812 li(at, rt);
813 div(rs, at);
814 }
815}
816
817
818void MacroAssembler::Ddiv(Register rs, const Operand& rt) {
819 if (rt.is_reg()) {
820 ddiv(rs, rt.rm());
821 } else {
822 // li handles the relocation.
823 DCHECK(!rs.is(at));
824 li(at, rt);
825 ddiv(rs, at);
826 }
827}
828
829
830void MacroAssembler::Ddiv(Register rd, Register rs, const Operand& rt) {
831 if (kArchVariant != kMips64r6) {
832 if (rt.is_reg()) {
833 ddiv(rs, rt.rm());
834 mflo(rd);
835 } else {
836 // li handles the relocation.
837 DCHECK(!rs.is(at));
838 li(at, rt);
839 ddiv(rs, at);
840 mflo(rd);
841 }
842 } else {
843 if (rt.is_reg()) {
844 ddiv(rd, rs, rt.rm());
845 } else {
846 // li handles the relocation.
847 DCHECK(!rs.is(at));
848 li(at, rt);
849 ddiv(rd, rs, at);
850 }
851 }
852}
853
854
855void MacroAssembler::Divu(Register rs, const Operand& rt) {
856 if (rt.is_reg()) {
857 divu(rs, rt.rm());
858 } else {
859 // li handles the relocation.
860 DCHECK(!rs.is(at));
861 li(at, rt);
862 divu(rs, at);
863 }
864}
865
866
867void MacroAssembler::Ddivu(Register rs, const Operand& rt) {
868 if (rt.is_reg()) {
869 ddivu(rs, rt.rm());
870 } else {
871 // li handles the relocation.
872 DCHECK(!rs.is(at));
873 li(at, rt);
874 ddivu(rs, at);
875 }
876}
877
878
879void MacroAssembler::Dmod(Register rd, Register rs, const Operand& rt) {
880 if (kArchVariant != kMips64r6) {
881 if (rt.is_reg()) {
882 ddiv(rs, rt.rm());
883 mfhi(rd);
884 } else {
885 // li handles the relocation.
886 DCHECK(!rs.is(at));
887 li(at, rt);
888 ddiv(rs, at);
889 mfhi(rd);
890 }
891 } else {
892 if (rt.is_reg()) {
893 dmod(rd, rs, rt.rm());
894 } else {
895 // li handles the relocation.
896 DCHECK(!rs.is(at));
897 li(at, rt);
898 dmod(rd, rs, at);
899 }
900 }
901}
902
903
904void MacroAssembler::And(Register rd, Register rs, const Operand& rt) {
905 if (rt.is_reg()) {
906 and_(rd, rs, rt.rm());
907 } else {
908 if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
909 andi(rd, rs, rt.imm64_);
910 } else {
911 // li handles the relocation.
912 DCHECK(!rs.is(at));
913 li(at, rt);
914 and_(rd, rs, at);
915 }
916 }
917}
918
919
920void MacroAssembler::Or(Register rd, Register rs, const Operand& rt) {
921 if (rt.is_reg()) {
922 or_(rd, rs, rt.rm());
923 } else {
924 if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
925 ori(rd, rs, rt.imm64_);
926 } else {
927 // li handles the relocation.
928 DCHECK(!rs.is(at));
929 li(at, rt);
930 or_(rd, rs, at);
931 }
932 }
933}
934
935
936void MacroAssembler::Xor(Register rd, Register rs, const Operand& rt) {
937 if (rt.is_reg()) {
938 xor_(rd, rs, rt.rm());
939 } else {
940 if (is_uint16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
941 xori(rd, rs, rt.imm64_);
942 } else {
943 // li handles the relocation.
944 DCHECK(!rs.is(at));
945 li(at, rt);
946 xor_(rd, rs, at);
947 }
948 }
949}
950
951
952void MacroAssembler::Nor(Register rd, Register rs, const Operand& rt) {
953 if (rt.is_reg()) {
954 nor(rd, rs, rt.rm());
955 } else {
956 // li handles the relocation.
957 DCHECK(!rs.is(at));
958 li(at, rt);
959 nor(rd, rs, at);
960 }
961}
962
963
964void MacroAssembler::Neg(Register rs, const Operand& rt) {
965 DCHECK(rt.is_reg());
966 DCHECK(!at.is(rs));
967 DCHECK(!at.is(rt.rm()));
968 li(at, -1);
969 xor_(rs, rt.rm(), at);
970}
971
972
973void MacroAssembler::Slt(Register rd, Register rs, const Operand& rt) {
974 if (rt.is_reg()) {
975 slt(rd, rs, rt.rm());
976 } else {
977 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
978 slti(rd, rs, rt.imm64_);
979 } else {
980 // li handles the relocation.
981 DCHECK(!rs.is(at));
982 li(at, rt);
983 slt(rd, rs, at);
984 }
985 }
986}
987
988
989void MacroAssembler::Sltu(Register rd, Register rs, const Operand& rt) {
990 if (rt.is_reg()) {
991 sltu(rd, rs, rt.rm());
992 } else {
993 if (is_int16(rt.imm64_) && !MustUseReg(rt.rmode_)) {
994 sltiu(rd, rs, rt.imm64_);
995 } else {
996 // li handles the relocation.
997 DCHECK(!rs.is(at));
998 li(at, rt);
999 sltu(rd, rs, at);
1000 }
1001 }
1002}
1003
1004
1005void MacroAssembler::Ror(Register rd, Register rs, const Operand& rt) {
1006 if (kArchVariant == kMips64r2) {
1007 if (rt.is_reg()) {
1008 rotrv(rd, rs, rt.rm());
1009 } else {
1010 rotr(rd, rs, rt.imm64_);
1011 }
1012 } else {
1013 if (rt.is_reg()) {
1014 subu(at, zero_reg, rt.rm());
1015 sllv(at, rs, at);
1016 srlv(rd, rs, rt.rm());
1017 or_(rd, rd, at);
1018 } else {
1019 if (rt.imm64_ == 0) {
1020 srl(rd, rs, 0);
1021 } else {
1022 srl(at, rs, rt.imm64_);
1023 sll(rd, rs, (0x20 - rt.imm64_) & 0x1f);
1024 or_(rd, rd, at);
1025 }
1026 }
1027 }
1028}
1029
1030
1031void MacroAssembler::Dror(Register rd, Register rs, const Operand& rt) {
1032 if (rt.is_reg()) {
1033 drotrv(rd, rs, rt.rm());
1034 } else {
1035 drotr(rd, rs, rt.imm64_);
1036 }
1037}
1038
1039
1040void MacroAssembler::Pref(int32_t hint, const MemOperand& rs) {
1041 pref(hint, rs);
1042}
1043
1044
1045// ------------Pseudo-instructions-------------
1046
1047void MacroAssembler::Ulw(Register rd, const MemOperand& rs) {
1048 lwr(rd, rs);
1049 lwl(rd, MemOperand(rs.rm(), rs.offset() + 3));
1050}
1051
1052
1053void MacroAssembler::Usw(Register rd, const MemOperand& rs) {
1054 swr(rd, rs);
1055 swl(rd, MemOperand(rs.rm(), rs.offset() + 3));
1056}
1057
1058
1059// Do 64-bit load from unaligned address. Note this only handles
1060// the specific case of 32-bit aligned, but not 64-bit aligned.
1061void MacroAssembler::Uld(Register rd, const MemOperand& rs, Register scratch) {
1062 // Assert fail if the offset from start of object IS actually aligned.
1063 // ONLY use with known misalignment, since there is performance cost.
1064 DCHECK((rs.offset() + kHeapObjectTag) & (kPointerSize - 1));
1065 // TODO(plind): endian dependency.
1066 lwu(rd, rs);
1067 lw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
1068 dsll32(scratch, scratch, 0);
1069 Daddu(rd, rd, scratch);
1070}
1071
1072
1073// Do 64-bit store to unaligned address. Note this only handles
1074// the specific case of 32-bit aligned, but not 64-bit aligned.
1075void MacroAssembler::Usd(Register rd, const MemOperand& rs, Register scratch) {
1076 // Assert fail if the offset from start of object IS actually aligned.
1077 // ONLY use with known misalignment, since there is performance cost.
1078 DCHECK((rs.offset() + kHeapObjectTag) & (kPointerSize - 1));
1079 // TODO(plind): endian dependency.
1080 sw(rd, rs);
1081 dsrl32(scratch, rd, 0);
1082 sw(scratch, MemOperand(rs.rm(), rs.offset() + kPointerSize / 2));
1083}
1084
1085
1086void MacroAssembler::li(Register dst, Handle<Object> value, LiFlags mode) {
1087 AllowDeferredHandleDereference smi_check;
1088 if (value->IsSmi()) {
1089 li(dst, Operand(value), mode);
1090 } else {
1091 DCHECK(value->IsHeapObject());
1092 if (isolate()->heap()->InNewSpace(*value)) {
1093 Handle<Cell> cell = isolate()->factory()->NewCell(value);
1094 li(dst, Operand(cell));
1095 ld(dst, FieldMemOperand(dst, Cell::kValueOffset));
1096 } else {
1097 li(dst, Operand(value));
1098 }
1099 }
1100}
1101
1102
1103void MacroAssembler::li(Register rd, Operand j, LiFlags mode) {
1104 DCHECK(!j.is_reg());
1105 BlockTrampolinePoolScope block_trampoline_pool(this);
1106 if (!MustUseReg(j.rmode_) && mode == OPTIMIZE_SIZE) {
1107 // Normal load of an immediate value which does not need Relocation Info.
1108 if (is_int32(j.imm64_)) {
1109 if (is_int16(j.imm64_)) {
1110 daddiu(rd, zero_reg, (j.imm64_ & kImm16Mask));
1111 } else if (!(j.imm64_ & kHiMask)) {
1112 ori(rd, zero_reg, (j.imm64_ & kImm16Mask));
1113 } else if (!(j.imm64_ & kImm16Mask)) {
1114 lui(rd, (j.imm64_ >> kLuiShift) & kImm16Mask);
1115 } else {
1116 lui(rd, (j.imm64_ >> kLuiShift) & kImm16Mask);
1117 ori(rd, rd, (j.imm64_ & kImm16Mask));
1118 }
1119 } else {
1120 lui(rd, (j.imm64_ >> 48) & kImm16Mask);
1121 ori(rd, rd, (j.imm64_ >> 32) & kImm16Mask);
1122 dsll(rd, rd, 16);
1123 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1124 dsll(rd, rd, 16);
1125 ori(rd, rd, j.imm64_ & kImm16Mask);
1126 }
1127 } else if (MustUseReg(j.rmode_)) {
1128 RecordRelocInfo(j.rmode_, j.imm64_);
1129 lui(rd, (j.imm64_ >> 32) & kImm16Mask);
1130 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1131 dsll(rd, rd, 16);
1132 ori(rd, rd, j.imm64_ & kImm16Mask);
1133 } else if (mode == ADDRESS_LOAD) {
1134 // We always need the same number of instructions as we may need to patch
1135 // this code to load another value which may need all 4 instructions.
1136 lui(rd, (j.imm64_ >> 32) & kImm16Mask);
1137 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1138 dsll(rd, rd, 16);
1139 ori(rd, rd, j.imm64_ & kImm16Mask);
1140 } else {
1141 lui(rd, (j.imm64_ >> 48) & kImm16Mask);
1142 ori(rd, rd, (j.imm64_ >> 32) & kImm16Mask);
1143 dsll(rd, rd, 16);
1144 ori(rd, rd, (j.imm64_ >> 16) & kImm16Mask);
1145 dsll(rd, rd, 16);
1146 ori(rd, rd, j.imm64_ & kImm16Mask);
1147 }
1148}
1149
1150
1151void MacroAssembler::MultiPush(RegList regs) {
1152 int16_t num_to_push = NumberOfBitsSet(regs);
1153 int16_t stack_offset = num_to_push * kPointerSize;
1154
1155 Dsubu(sp, sp, Operand(stack_offset));
1156 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1157 if ((regs & (1 << i)) != 0) {
1158 stack_offset -= kPointerSize;
1159 sd(ToRegister(i), MemOperand(sp, stack_offset));
1160 }
1161 }
1162}
1163
1164
1165void MacroAssembler::MultiPushReversed(RegList regs) {
1166 int16_t num_to_push = NumberOfBitsSet(regs);
1167 int16_t stack_offset = num_to_push * kPointerSize;
1168
1169 Dsubu(sp, sp, Operand(stack_offset));
1170 for (int16_t i = 0; i < kNumRegisters; i++) {
1171 if ((regs & (1 << i)) != 0) {
1172 stack_offset -= kPointerSize;
1173 sd(ToRegister(i), MemOperand(sp, stack_offset));
1174 }
1175 }
1176}
1177
1178
1179void MacroAssembler::MultiPop(RegList regs) {
1180 int16_t stack_offset = 0;
1181
1182 for (int16_t i = 0; i < kNumRegisters; i++) {
1183 if ((regs & (1 << i)) != 0) {
1184 ld(ToRegister(i), MemOperand(sp, stack_offset));
1185 stack_offset += kPointerSize;
1186 }
1187 }
1188 daddiu(sp, sp, stack_offset);
1189}
1190
1191
1192void MacroAssembler::MultiPopReversed(RegList regs) {
1193 int16_t stack_offset = 0;
1194
1195 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1196 if ((regs & (1 << i)) != 0) {
1197 ld(ToRegister(i), MemOperand(sp, stack_offset));
1198 stack_offset += kPointerSize;
1199 }
1200 }
1201 daddiu(sp, sp, stack_offset);
1202}
1203
1204
1205void MacroAssembler::MultiPushFPU(RegList regs) {
1206 int16_t num_to_push = NumberOfBitsSet(regs);
1207 int16_t stack_offset = num_to_push * kDoubleSize;
1208
1209 Dsubu(sp, sp, Operand(stack_offset));
1210 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1211 if ((regs & (1 << i)) != 0) {
1212 stack_offset -= kDoubleSize;
1213 sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1214 }
1215 }
1216}
1217
1218
1219void MacroAssembler::MultiPushReversedFPU(RegList regs) {
1220 int16_t num_to_push = NumberOfBitsSet(regs);
1221 int16_t stack_offset = num_to_push * kDoubleSize;
1222
1223 Dsubu(sp, sp, Operand(stack_offset));
1224 for (int16_t i = 0; i < kNumRegisters; i++) {
1225 if ((regs & (1 << i)) != 0) {
1226 stack_offset -= kDoubleSize;
1227 sdc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1228 }
1229 }
1230}
1231
1232
1233void MacroAssembler::MultiPopFPU(RegList regs) {
1234 int16_t stack_offset = 0;
1235
1236 for (int16_t i = 0; i < kNumRegisters; i++) {
1237 if ((regs & (1 << i)) != 0) {
1238 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1239 stack_offset += kDoubleSize;
1240 }
1241 }
1242 daddiu(sp, sp, stack_offset);
1243}
1244
1245
1246void MacroAssembler::MultiPopReversedFPU(RegList regs) {
1247 int16_t stack_offset = 0;
1248
1249 for (int16_t i = kNumRegisters - 1; i >= 0; i--) {
1250 if ((regs & (1 << i)) != 0) {
1251 ldc1(FPURegister::from_code(i), MemOperand(sp, stack_offset));
1252 stack_offset += kDoubleSize;
1253 }
1254 }
1255 daddiu(sp, sp, stack_offset);
1256}
1257
1258
1259void MacroAssembler::FlushICache(Register address, unsigned instructions) {
1260 RegList saved_regs = kJSCallerSaved | ra.bit();
1261 MultiPush(saved_regs);
1262 AllowExternalCallThatCantCauseGC scope(this);
1263
1264 // Save to a0 in case address == a4.
1265 Move(a0, address);
1266 PrepareCallCFunction(2, a4);
1267
1268 li(a1, instructions * kInstrSize);
1269 CallCFunction(ExternalReference::flush_icache_function(isolate()), 2);
1270 MultiPop(saved_regs);
1271}
1272
1273
1274void MacroAssembler::Ext(Register rt,
1275 Register rs,
1276 uint16_t pos,
1277 uint16_t size) {
1278 DCHECK(pos < 32);
1279 DCHECK(pos + size < 33);
1280 ext_(rt, rs, pos, size);
1281}
1282
1283
1284void MacroAssembler::Ins(Register rt,
1285 Register rs,
1286 uint16_t pos,
1287 uint16_t size) {
1288 DCHECK(pos < 32);
1289 DCHECK(pos + size <= 32);
1290 DCHECK(size != 0);
1291 ins_(rt, rs, pos, size);
1292}
1293
1294
1295void MacroAssembler::Cvt_d_uw(FPURegister fd,
1296 FPURegister fs,
1297 FPURegister scratch) {
1298 // Move the data from fs to t8.
1299 mfc1(t8, fs);
1300 Cvt_d_uw(fd, t8, scratch);
1301}
1302
1303
1304void MacroAssembler::Cvt_d_uw(FPURegister fd,
1305 Register rs,
1306 FPURegister scratch) {
1307 // Convert rs to a FP value in fd (and fd + 1).
1308 // We do this by converting rs minus the MSB to avoid sign conversion,
1309 // then adding 2^31 to the result (if needed).
1310
1311 DCHECK(!fd.is(scratch));
1312 DCHECK(!rs.is(t9));
1313 DCHECK(!rs.is(at));
1314
1315 // Save rs's MSB to t9.
1316 Ext(t9, rs, 31, 1);
1317 // Remove rs's MSB.
1318 Ext(at, rs, 0, 31);
1319 // Move the result to fd.
1320 mtc1(at, fd);
1321 mthc1(zero_reg, fd);
1322
1323 // Convert fd to a real FP value.
1324 cvt_d_w(fd, fd);
1325
1326 Label conversion_done;
1327
1328 // If rs's MSB was 0, it's done.
1329 // Otherwise we need to add that to the FP register.
1330 Branch(&conversion_done, eq, t9, Operand(zero_reg));
1331
1332 // Load 2^31 into f20 as its float representation.
1333 li(at, 0x41E00000);
1334 mtc1(zero_reg, scratch);
1335 mthc1(at, scratch);
1336 // Add it to fd.
1337 add_d(fd, fd, scratch);
1338
1339 bind(&conversion_done);
1340}
1341
1342
1343void MacroAssembler::Round_l_d(FPURegister fd, FPURegister fs) {
1344 round_l_d(fd, fs);
1345}
1346
1347
1348void MacroAssembler::Floor_l_d(FPURegister fd, FPURegister fs) {
1349 floor_l_d(fd, fs);
1350}
1351
1352
1353void MacroAssembler::Ceil_l_d(FPURegister fd, FPURegister fs) {
1354 ceil_l_d(fd, fs);
1355}
1356
1357
1358void MacroAssembler::Trunc_l_d(FPURegister fd, FPURegister fs) {
1359 trunc_l_d(fd, fs);
1360}
1361
1362
1363void MacroAssembler::Trunc_l_ud(FPURegister fd,
1364 FPURegister fs,
1365 FPURegister scratch) {
1366 // Load to GPR.
1367 dmfc1(t8, fs);
1368 // Reset sign bit.
1369 li(at, 0x7fffffffffffffff);
1370 and_(t8, t8, at);
1371 dmtc1(t8, fs);
1372 trunc_l_d(fd, fs);
1373}
1374
1375
1376void MacroAssembler::Trunc_uw_d(FPURegister fd,
1377 FPURegister fs,
1378 FPURegister scratch) {
1379 Trunc_uw_d(fs, t8, scratch);
1380 mtc1(t8, fd);
1381}
1382
1383
1384void MacroAssembler::Trunc_w_d(FPURegister fd, FPURegister fs) {
1385 trunc_w_d(fd, fs);
1386}
1387
1388
1389void MacroAssembler::Round_w_d(FPURegister fd, FPURegister fs) {
1390 round_w_d(fd, fs);
1391}
1392
1393
1394void MacroAssembler::Floor_w_d(FPURegister fd, FPURegister fs) {
1395 floor_w_d(fd, fs);
1396}
1397
1398
1399void MacroAssembler::Ceil_w_d(FPURegister fd, FPURegister fs) {
1400 ceil_w_d(fd, fs);
1401}
1402
1403
1404void MacroAssembler::Trunc_uw_d(FPURegister fd,
1405 Register rs,
1406 FPURegister scratch) {
1407 DCHECK(!fd.is(scratch));
1408 DCHECK(!rs.is(at));
1409
1410 // Load 2^31 into scratch as its float representation.
1411 li(at, 0x41E00000);
1412 mtc1(zero_reg, scratch);
1413 mthc1(at, scratch);
1414 // Test if scratch > fd.
1415 // If fd < 2^31 we can convert it normally.
1416 Label simple_convert;
1417 BranchF(&simple_convert, NULL, lt, fd, scratch);
1418
1419 // First we subtract 2^31 from fd, then trunc it to rs
1420 // and add 2^31 to rs.
1421 sub_d(scratch, fd, scratch);
1422 trunc_w_d(scratch, scratch);
1423 mfc1(rs, scratch);
1424 Or(rs, rs, 1 << 31);
1425
1426 Label done;
1427 Branch(&done);
1428 // Simple conversion.
1429 bind(&simple_convert);
1430 trunc_w_d(scratch, fd);
1431 mfc1(rs, scratch);
1432
1433 bind(&done);
1434}
1435
1436
1437void MacroAssembler::Madd_d(FPURegister fd, FPURegister fr, FPURegister fs,
1438 FPURegister ft, FPURegister scratch) {
1439 if (0) { // TODO(plind): find reasonable arch-variant symbol names.
1440 madd_d(fd, fr, fs, ft);
1441 } else {
1442 // Can not change source regs's value.
1443 DCHECK(!fr.is(scratch) && !fs.is(scratch) && !ft.is(scratch));
1444 mul_d(scratch, fs, ft);
1445 add_d(fd, fr, scratch);
1446 }
1447}
1448
1449
1450void MacroAssembler::BranchF(Label* target,
1451 Label* nan,
1452 Condition cc,
1453 FPURegister cmp1,
1454 FPURegister cmp2,
1455 BranchDelaySlot bd) {
1456 BlockTrampolinePoolScope block_trampoline_pool(this);
1457 if (cc == al) {
1458 Branch(bd, target);
1459 return;
1460 }
1461
1462 DCHECK(nan || target);
1463 // Check for unordered (NaN) cases.
1464 if (nan) {
1465 if (kArchVariant != kMips64r6) {
1466 c(UN, D, cmp1, cmp2);
1467 bc1t(nan);
1468 } else {
1469 // Use f31 for comparison result. It has to be unavailable to lithium
1470 // register allocator.
1471 DCHECK(!cmp1.is(f31) && !cmp2.is(f31));
1472 cmp(UN, L, f31, cmp1, cmp2);
1473 bc1nez(nan, f31);
1474 }
1475 }
1476
1477 if (kArchVariant != kMips64r6) {
1478 if (target) {
1479 // Here NaN cases were either handled by this function or are assumed to
1480 // have been handled by the caller.
1481 switch (cc) {
1482 case lt:
1483 c(OLT, D, cmp1, cmp2);
1484 bc1t(target);
1485 break;
1486 case gt:
1487 c(ULE, D, cmp1, cmp2);
1488 bc1f(target);
1489 break;
1490 case ge:
1491 c(ULT, D, cmp1, cmp2);
1492 bc1f(target);
1493 break;
1494 case le:
1495 c(OLE, D, cmp1, cmp2);
1496 bc1t(target);
1497 break;
1498 case eq:
1499 c(EQ, D, cmp1, cmp2);
1500 bc1t(target);
1501 break;
1502 case ueq:
1503 c(UEQ, D, cmp1, cmp2);
1504 bc1t(target);
1505 break;
1506 case ne:
1507 c(EQ, D, cmp1, cmp2);
1508 bc1f(target);
1509 break;
1510 case nue:
1511 c(UEQ, D, cmp1, cmp2);
1512 bc1f(target);
1513 break;
1514 default:
1515 CHECK(0);
1516 }
1517 }
1518 } else {
1519 if (target) {
1520 // Here NaN cases were either handled by this function or are assumed to
1521 // have been handled by the caller.
1522 // Unsigned conditions are treated as their signed counterpart.
1523 // Use f31 for comparison result, it is valid in fp64 (FR = 1) mode.
1524 DCHECK(!cmp1.is(f31) && !cmp2.is(f31));
1525 switch (cc) {
1526 case lt:
1527 cmp(OLT, L, f31, cmp1, cmp2);
1528 bc1nez(target, f31);
1529 break;
1530 case gt:
1531 cmp(ULE, L, f31, cmp1, cmp2);
1532 bc1eqz(target, f31);
1533 break;
1534 case ge:
1535 cmp(ULT, L, f31, cmp1, cmp2);
1536 bc1eqz(target, f31);
1537 break;
1538 case le:
1539 cmp(OLE, L, f31, cmp1, cmp2);
1540 bc1nez(target, f31);
1541 break;
1542 case eq:
1543 cmp(EQ, L, f31, cmp1, cmp2);
1544 bc1nez(target, f31);
1545 break;
1546 case ueq:
1547 cmp(UEQ, L, f31, cmp1, cmp2);
1548 bc1nez(target, f31);
1549 break;
1550 case ne:
1551 cmp(EQ, L, f31, cmp1, cmp2);
1552 bc1eqz(target, f31);
1553 break;
1554 case nue:
1555 cmp(UEQ, L, f31, cmp1, cmp2);
1556 bc1eqz(target, f31);
1557 break;
1558 default:
1559 CHECK(0);
1560 }
1561 }
1562 }
1563
1564 if (bd == PROTECT) {
1565 nop();
1566 }
1567}
1568
1569
1570void MacroAssembler::Move(FPURegister dst, double imm) {
1571 static const DoubleRepresentation minus_zero(-0.0);
1572 static const DoubleRepresentation zero(0.0);
1573 DoubleRepresentation value_rep(imm);
1574 // Handle special values first.
1575 bool force_load = dst.is(kDoubleRegZero);
1576 if (value_rep == zero && !force_load) {
1577 mov_d(dst, kDoubleRegZero);
1578 } else if (value_rep == minus_zero && !force_load) {
1579 neg_d(dst, kDoubleRegZero);
1580 } else {
1581 uint32_t lo, hi;
1582 DoubleAsTwoUInt32(imm, &lo, &hi);
1583 // Move the low part of the double into the lower bits of the corresponding
1584 // FPU register.
1585 if (lo != 0) {
1586 li(at, Operand(lo));
1587 mtc1(at, dst);
1588 } else {
1589 mtc1(zero_reg, dst);
1590 }
1591 // Move the high part of the double into the high bits of the corresponding
1592 // FPU register.
1593 if (hi != 0) {
1594 li(at, Operand(hi));
1595 mthc1(at, dst);
1596 } else {
1597 mthc1(zero_reg, dst);
1598 }
1599 }
1600}
1601
1602
1603void MacroAssembler::Movz(Register rd, Register rs, Register rt) {
1604 if (kArchVariant == kMips64r6) {
1605 Label done;
1606 Branch(&done, ne, rt, Operand(zero_reg));
1607 mov(rd, rs);
1608 bind(&done);
1609 } else {
1610 movz(rd, rs, rt);
1611 }
1612}
1613
1614
1615void MacroAssembler::Movn(Register rd, Register rs, Register rt) {
1616 if (kArchVariant == kMips64r6) {
1617 Label done;
1618 Branch(&done, eq, rt, Operand(zero_reg));
1619 mov(rd, rs);
1620 bind(&done);
1621 } else {
1622 movn(rd, rs, rt);
1623 }
1624}
1625
1626
1627void MacroAssembler::Movt(Register rd, Register rs, uint16_t cc) {
1628 movt(rd, rs, cc);
1629}
1630
1631
1632void MacroAssembler::Movf(Register rd, Register rs, uint16_t cc) {
1633 movf(rd, rs, cc);
1634}
1635
1636
1637void MacroAssembler::Clz(Register rd, Register rs) {
1638 clz(rd, rs);
1639}
1640
1641
1642void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
1643 Register result,
1644 DoubleRegister double_input,
1645 Register scratch,
1646 DoubleRegister double_scratch,
1647 Register except_flag,
1648 CheckForInexactConversion check_inexact) {
1649 DCHECK(!result.is(scratch));
1650 DCHECK(!double_input.is(double_scratch));
1651 DCHECK(!except_flag.is(scratch));
1652
1653 Label done;
1654
1655 // Clear the except flag (0 = no exception)
1656 mov(except_flag, zero_reg);
1657
1658 // Test for values that can be exactly represented as a signed 32-bit integer.
1659 cvt_w_d(double_scratch, double_input);
1660 mfc1(result, double_scratch);
1661 cvt_d_w(double_scratch, double_scratch);
1662 BranchF(&done, NULL, eq, double_input, double_scratch);
1663
1664 int32_t except_mask = kFCSRFlagMask; // Assume interested in all exceptions.
1665
1666 if (check_inexact == kDontCheckForInexactConversion) {
1667 // Ignore inexact exceptions.
1668 except_mask &= ~kFCSRInexactFlagMask;
1669 }
1670
1671 // Save FCSR.
1672 cfc1(scratch, FCSR);
1673 // Disable FPU exceptions.
1674 ctc1(zero_reg, FCSR);
1675
1676 // Do operation based on rounding mode.
1677 switch (rounding_mode) {
1678 case kRoundToNearest:
1679 Round_w_d(double_scratch, double_input);
1680 break;
1681 case kRoundToZero:
1682 Trunc_w_d(double_scratch, double_input);
1683 break;
1684 case kRoundToPlusInf:
1685 Ceil_w_d(double_scratch, double_input);
1686 break;
1687 case kRoundToMinusInf:
1688 Floor_w_d(double_scratch, double_input);
1689 break;
1690 } // End of switch-statement.
1691
1692 // Retrieve FCSR.
1693 cfc1(except_flag, FCSR);
1694 // Restore FCSR.
1695 ctc1(scratch, FCSR);
1696 // Move the converted value into the result register.
1697 mfc1(result, double_scratch);
1698
1699 // Check for fpu exceptions.
1700 And(except_flag, except_flag, Operand(except_mask));
1701
1702 bind(&done);
1703}
1704
1705
1706void MacroAssembler::TryInlineTruncateDoubleToI(Register result,
1707 DoubleRegister double_input,
1708 Label* done) {
1709 DoubleRegister single_scratch = kLithiumScratchDouble.low();
1710 Register scratch = at;
1711 Register scratch2 = t9;
1712
1713 // Clear cumulative exception flags and save the FCSR.
1714 cfc1(scratch2, FCSR);
1715 ctc1(zero_reg, FCSR);
1716 // Try a conversion to a signed integer.
1717 trunc_w_d(single_scratch, double_input);
1718 mfc1(result, single_scratch);
1719 // Retrieve and restore the FCSR.
1720 cfc1(scratch, FCSR);
1721 ctc1(scratch2, FCSR);
1722 // Check for overflow and NaNs.
1723 And(scratch,
1724 scratch,
1725 kFCSROverflowFlagMask | kFCSRUnderflowFlagMask | kFCSRInvalidOpFlagMask);
1726 // If we had no exceptions we are done.
1727 Branch(done, eq, scratch, Operand(zero_reg));
1728}
1729
1730
1731void MacroAssembler::TruncateDoubleToI(Register result,
1732 DoubleRegister double_input) {
1733 Label done;
1734
1735 TryInlineTruncateDoubleToI(result, double_input, &done);
1736
1737 // If we fell through then inline version didn't succeed - call stub instead.
1738 push(ra);
1739 Dsubu(sp, sp, Operand(kDoubleSize)); // Put input on stack.
1740 sdc1(double_input, MemOperand(sp, 0));
1741
1742 DoubleToIStub stub(isolate(), sp, result, 0, true, true);
1743 CallStub(&stub);
1744
1745 Daddu(sp, sp, Operand(kDoubleSize));
1746 pop(ra);
1747
1748 bind(&done);
1749}
1750
1751
1752void MacroAssembler::TruncateHeapNumberToI(Register result, Register object) {
1753 Label done;
1754 DoubleRegister double_scratch = f12;
1755 DCHECK(!result.is(object));
1756
1757 ldc1(double_scratch,
1758 MemOperand(object, HeapNumber::kValueOffset - kHeapObjectTag));
1759 TryInlineTruncateDoubleToI(result, double_scratch, &done);
1760
1761 // If we fell through then inline version didn't succeed - call stub instead.
1762 push(ra);
1763 DoubleToIStub stub(isolate(),
1764 object,
1765 result,
1766 HeapNumber::kValueOffset - kHeapObjectTag,
1767 true,
1768 true);
1769 CallStub(&stub);
1770 pop(ra);
1771
1772 bind(&done);
1773}
1774
1775
1776void MacroAssembler::TruncateNumberToI(Register object,
1777 Register result,
1778 Register heap_number_map,
1779 Register scratch,
1780 Label* not_number) {
1781 Label done;
1782 DCHECK(!result.is(object));
1783
1784 UntagAndJumpIfSmi(result, object, &done);
1785 JumpIfNotHeapNumber(object, heap_number_map, scratch, not_number);
1786 TruncateHeapNumberToI(result, object);
1787
1788 bind(&done);
1789}
1790
1791
1792void MacroAssembler::GetLeastBitsFromSmi(Register dst,
1793 Register src,
1794 int num_least_bits) {
1795 // Ext(dst, src, kSmiTagSize, num_least_bits);
1796 SmiUntag(dst, src);
1797 And(dst, dst, Operand((1 << num_least_bits) - 1));
1798}
1799
1800
1801void MacroAssembler::GetLeastBitsFromInt32(Register dst,
1802 Register src,
1803 int num_least_bits) {
1804 DCHECK(!src.is(dst));
1805 And(dst, src, Operand((1 << num_least_bits) - 1));
1806}
1807
1808
1809// Emulated condtional branches do not emit a nop in the branch delay slot.
1810//
1811// BRANCH_ARGS_CHECK checks that conditional jump arguments are correct.
1812#define BRANCH_ARGS_CHECK(cond, rs, rt) DCHECK( \
1813 (cond == cc_always && rs.is(zero_reg) && rt.rm().is(zero_reg)) || \
1814 (cond != cc_always && (!rs.is(zero_reg) || !rt.rm().is(zero_reg))))
1815
1816
1817void MacroAssembler::Branch(int16_t offset, BranchDelaySlot bdslot) {
1818 BranchShort(offset, bdslot);
1819}
1820
1821
1822void MacroAssembler::Branch(int16_t offset, Condition cond, Register rs,
1823 const Operand& rt,
1824 BranchDelaySlot bdslot) {
1825 BranchShort(offset, cond, rs, rt, bdslot);
1826}
1827
1828
1829void MacroAssembler::Branch(Label* L, BranchDelaySlot bdslot) {
1830 if (L->is_bound()) {
1831 if (is_near(L)) {
1832 BranchShort(L, bdslot);
1833 } else {
1834 Jr(L, bdslot);
1835 }
1836 } else {
1837 if (is_trampoline_emitted()) {
1838 Jr(L, bdslot);
1839 } else {
1840 BranchShort(L, bdslot);
1841 }
1842 }
1843}
1844
1845
1846void MacroAssembler::Branch(Label* L, Condition cond, Register rs,
1847 const Operand& rt,
1848 BranchDelaySlot bdslot) {
1849 if (L->is_bound()) {
1850 if (is_near(L)) {
1851 BranchShort(L, cond, rs, rt, bdslot);
1852 } else {
1853 if (cond != cc_always) {
1854 Label skip;
1855 Condition neg_cond = NegateCondition(cond);
1856 BranchShort(&skip, neg_cond, rs, rt);
1857 Jr(L, bdslot);
1858 bind(&skip);
1859 } else {
1860 Jr(L, bdslot);
1861 }
1862 }
1863 } else {
1864 if (is_trampoline_emitted()) {
1865 if (cond != cc_always) {
1866 Label skip;
1867 Condition neg_cond = NegateCondition(cond);
1868 BranchShort(&skip, neg_cond, rs, rt);
1869 Jr(L, bdslot);
1870 bind(&skip);
1871 } else {
1872 Jr(L, bdslot);
1873 }
1874 } else {
1875 BranchShort(L, cond, rs, rt, bdslot);
1876 }
1877 }
1878}
1879
1880
1881void MacroAssembler::Branch(Label* L,
1882 Condition cond,
1883 Register rs,
1884 Heap::RootListIndex index,
1885 BranchDelaySlot bdslot) {
1886 LoadRoot(at, index);
1887 Branch(L, cond, rs, Operand(at), bdslot);
1888}
1889
1890
1891void MacroAssembler::BranchShort(int16_t offset, BranchDelaySlot bdslot) {
1892 b(offset);
1893
1894 // Emit a nop in the branch delay slot if required.
1895 if (bdslot == PROTECT)
1896 nop();
1897}
1898
1899
1900void MacroAssembler::BranchShort(int16_t offset, Condition cond, Register rs,
1901 const Operand& rt,
1902 BranchDelaySlot bdslot) {
1903 BRANCH_ARGS_CHECK(cond, rs, rt);
1904 DCHECK(!rs.is(zero_reg));
1905 Register r2 = no_reg;
1906 Register scratch = at;
1907
1908 if (rt.is_reg()) {
1909 // NOTE: 'at' can be clobbered by Branch but it is legal to use it as rs or
1910 // rt.
1911 BlockTrampolinePoolScope block_trampoline_pool(this);
1912 r2 = rt.rm_;
1913 switch (cond) {
1914 case cc_always:
1915 b(offset);
1916 break;
1917 case eq:
1918 beq(rs, r2, offset);
1919 break;
1920 case ne:
1921 bne(rs, r2, offset);
1922 break;
1923 // Signed comparison.
1924 case greater:
1925 if (r2.is(zero_reg)) {
1926 bgtz(rs, offset);
1927 } else {
1928 slt(scratch, r2, rs);
1929 bne(scratch, zero_reg, offset);
1930 }
1931 break;
1932 case greater_equal:
1933 if (r2.is(zero_reg)) {
1934 bgez(rs, offset);
1935 } else {
1936 slt(scratch, rs, r2);
1937 beq(scratch, zero_reg, offset);
1938 }
1939 break;
1940 case less:
1941 if (r2.is(zero_reg)) {
1942 bltz(rs, offset);
1943 } else {
1944 slt(scratch, rs, r2);
1945 bne(scratch, zero_reg, offset);
1946 }
1947 break;
1948 case less_equal:
1949 if (r2.is(zero_reg)) {
1950 blez(rs, offset);
1951 } else {
1952 slt(scratch, r2, rs);
1953 beq(scratch, zero_reg, offset);
1954 }
1955 break;
1956 // Unsigned comparison.
1957 case Ugreater:
1958 if (r2.is(zero_reg)) {
1959 bgtz(rs, offset);
1960 } else {
1961 sltu(scratch, r2, rs);
1962 bne(scratch, zero_reg, offset);
1963 }
1964 break;
1965 case Ugreater_equal:
1966 if (r2.is(zero_reg)) {
1967 bgez(rs, offset);
1968 } else {
1969 sltu(scratch, rs, r2);
1970 beq(scratch, zero_reg, offset);
1971 }
1972 break;
1973 case Uless:
1974 if (r2.is(zero_reg)) {
1975 // No code needs to be emitted.
1976 return;
1977 } else {
1978 sltu(scratch, rs, r2);
1979 bne(scratch, zero_reg, offset);
1980 }
1981 break;
1982 case Uless_equal:
1983 if (r2.is(zero_reg)) {
1984 b(offset);
1985 } else {
1986 sltu(scratch, r2, rs);
1987 beq(scratch, zero_reg, offset);
1988 }
1989 break;
1990 default:
1991 UNREACHABLE();
1992 }
1993 } else {
1994 // Be careful to always use shifted_branch_offset only just before the
1995 // branch instruction, as the location will be remember for patching the
1996 // target.
1997 BlockTrampolinePoolScope block_trampoline_pool(this);
1998 switch (cond) {
1999 case cc_always:
2000 b(offset);
2001 break;
2002 case eq:
2003 // We don't want any other register but scratch clobbered.
2004 DCHECK(!scratch.is(rs));
2005 r2 = scratch;
2006 li(r2, rt);
2007 beq(rs, r2, offset);
2008 break;
2009 case ne:
2010 // We don't want any other register but scratch clobbered.
2011 DCHECK(!scratch.is(rs));
2012 r2 = scratch;
2013 li(r2, rt);
2014 bne(rs, r2, offset);
2015 break;
2016 // Signed comparison.
2017 case greater:
2018 if (rt.imm64_ == 0) {
2019 bgtz(rs, offset);
2020 } else {
2021 r2 = scratch;
2022 li(r2, rt);
2023 slt(scratch, r2, rs);
2024 bne(scratch, zero_reg, offset);
2025 }
2026 break;
2027 case greater_equal:
2028 if (rt.imm64_ == 0) {
2029 bgez(rs, offset);
2030 } else if (is_int16(rt.imm64_)) {
2031 slti(scratch, rs, rt.imm64_);
2032 beq(scratch, zero_reg, offset);
2033 } else {
2034 r2 = scratch;
2035 li(r2, rt);
2036 slt(scratch, rs, r2);
2037 beq(scratch, zero_reg, offset);
2038 }
2039 break;
2040 case less:
2041 if (rt.imm64_ == 0) {
2042 bltz(rs, offset);
2043 } else if (is_int16(rt.imm64_)) {
2044 slti(scratch, rs, rt.imm64_);
2045 bne(scratch, zero_reg, offset);
2046 } else {
2047 r2 = scratch;
2048 li(r2, rt);
2049 slt(scratch, rs, r2);
2050 bne(scratch, zero_reg, offset);
2051 }
2052 break;
2053 case less_equal:
2054 if (rt.imm64_ == 0) {
2055 blez(rs, offset);
2056 } else {
2057 r2 = scratch;
2058 li(r2, rt);
2059 slt(scratch, r2, rs);
2060 beq(scratch, zero_reg, offset);
2061 }
2062 break;
2063 // Unsigned comparison.
2064 case Ugreater:
2065 if (rt.imm64_ == 0) {
2066 bgtz(rs, offset);
2067 } else {
2068 r2 = scratch;
2069 li(r2, rt);
2070 sltu(scratch, r2, rs);
2071 bne(scratch, zero_reg, offset);
2072 }
2073 break;
2074 case Ugreater_equal:
2075 if (rt.imm64_ == 0) {
2076 bgez(rs, offset);
2077 } else if (is_int16(rt.imm64_)) {
2078 sltiu(scratch, rs, rt.imm64_);
2079 beq(scratch, zero_reg, offset);
2080 } else {
2081 r2 = scratch;
2082 li(r2, rt);
2083 sltu(scratch, rs, r2);
2084 beq(scratch, zero_reg, offset);
2085 }
2086 break;
2087 case Uless:
2088 if (rt.imm64_ == 0) {
2089 // No code needs to be emitted.
2090 return;
2091 } else if (is_int16(rt.imm64_)) {
2092 sltiu(scratch, rs, rt.imm64_);
2093 bne(scratch, zero_reg, offset);
2094 } else {
2095 r2 = scratch;
2096 li(r2, rt);
2097 sltu(scratch, rs, r2);
2098 bne(scratch, zero_reg, offset);
2099 }
2100 break;
2101 case Uless_equal:
2102 if (rt.imm64_ == 0) {
2103 b(offset);
2104 } else {
2105 r2 = scratch;
2106 li(r2, rt);
2107 sltu(scratch, r2, rs);
2108 beq(scratch, zero_reg, offset);
2109 }
2110 break;
2111 default:
2112 UNREACHABLE();
2113 }
2114 }
2115 // Emit a nop in the branch delay slot if required.
2116 if (bdslot == PROTECT)
2117 nop();
2118}
2119
2120
2121void MacroAssembler::BranchShort(Label* L, BranchDelaySlot bdslot) {
2122 // We use branch_offset as an argument for the branch instructions to be sure
2123 // it is called just before generating the branch instruction, as needed.
2124
2125 b(shifted_branch_offset(L, false));
2126
2127 // Emit a nop in the branch delay slot if required.
2128 if (bdslot == PROTECT)
2129 nop();
2130}
2131
2132
2133void MacroAssembler::BranchShort(Label* L, Condition cond, Register rs,
2134 const Operand& rt,
2135 BranchDelaySlot bdslot) {
2136 BRANCH_ARGS_CHECK(cond, rs, rt);
2137
2138 int32_t offset = 0;
2139 Register r2 = no_reg;
2140 Register scratch = at;
2141 if (rt.is_reg()) {
2142 BlockTrampolinePoolScope block_trampoline_pool(this);
2143 r2 = rt.rm_;
2144 // Be careful to always use shifted_branch_offset only just before the
2145 // branch instruction, as the location will be remember for patching the
2146 // target.
2147 switch (cond) {
2148 case cc_always:
2149 offset = shifted_branch_offset(L, false);
2150 b(offset);
2151 break;
2152 case eq:
2153 offset = shifted_branch_offset(L, false);
2154 beq(rs, r2, offset);
2155 break;
2156 case ne:
2157 offset = shifted_branch_offset(L, false);
2158 bne(rs, r2, offset);
2159 break;
2160 // Signed comparison.
2161 case greater:
2162 if (r2.is(zero_reg)) {
2163 offset = shifted_branch_offset(L, false);
2164 bgtz(rs, offset);
2165 } else {
2166 slt(scratch, r2, rs);
2167 offset = shifted_branch_offset(L, false);
2168 bne(scratch, zero_reg, offset);
2169 }
2170 break;
2171 case greater_equal:
2172 if (r2.is(zero_reg)) {
2173 offset = shifted_branch_offset(L, false);
2174 bgez(rs, offset);
2175 } else {
2176 slt(scratch, rs, r2);
2177 offset = shifted_branch_offset(L, false);
2178 beq(scratch, zero_reg, offset);
2179 }
2180 break;
2181 case less:
2182 if (r2.is(zero_reg)) {
2183 offset = shifted_branch_offset(L, false);
2184 bltz(rs, offset);
2185 } else {
2186 slt(scratch, rs, r2);
2187 offset = shifted_branch_offset(L, false);
2188 bne(scratch, zero_reg, offset);
2189 }
2190 break;
2191 case less_equal:
2192 if (r2.is(zero_reg)) {
2193 offset = shifted_branch_offset(L, false);
2194 blez(rs, offset);
2195 } else {
2196 slt(scratch, r2, rs);
2197 offset = shifted_branch_offset(L, false);
2198 beq(scratch, zero_reg, offset);
2199 }
2200 break;
2201 // Unsigned comparison.
2202 case Ugreater:
2203 if (r2.is(zero_reg)) {
2204 offset = shifted_branch_offset(L, false);
2205 bgtz(rs, offset);
2206 } else {
2207 sltu(scratch, r2, rs);
2208 offset = shifted_branch_offset(L, false);
2209 bne(scratch, zero_reg, offset);
2210 }
2211 break;
2212 case Ugreater_equal:
2213 if (r2.is(zero_reg)) {
2214 offset = shifted_branch_offset(L, false);
2215 bgez(rs, offset);
2216 } else {
2217 sltu(scratch, rs, r2);
2218 offset = shifted_branch_offset(L, false);
2219 beq(scratch, zero_reg, offset);
2220 }
2221 break;
2222 case Uless:
2223 if (r2.is(zero_reg)) {
2224 // No code needs to be emitted.
2225 return;
2226 } else {
2227 sltu(scratch, rs, r2);
2228 offset = shifted_branch_offset(L, false);
2229 bne(scratch, zero_reg, offset);
2230 }
2231 break;
2232 case Uless_equal:
2233 if (r2.is(zero_reg)) {
2234 offset = shifted_branch_offset(L, false);
2235 b(offset);
2236 } else {
2237 sltu(scratch, r2, rs);
2238 offset = shifted_branch_offset(L, false);
2239 beq(scratch, zero_reg, offset);
2240 }
2241 break;
2242 default:
2243 UNREACHABLE();
2244 }
2245 } else {
2246 // Be careful to always use shifted_branch_offset only just before the
2247 // branch instruction, as the location will be remember for patching the
2248 // target.
2249 BlockTrampolinePoolScope block_trampoline_pool(this);
2250 switch (cond) {
2251 case cc_always:
2252 offset = shifted_branch_offset(L, false);
2253 b(offset);
2254 break;
2255 case eq:
2256 DCHECK(!scratch.is(rs));
2257 r2 = scratch;
2258 li(r2, rt);
2259 offset = shifted_branch_offset(L, false);
2260 beq(rs, r2, offset);
2261 break;
2262 case ne:
2263 DCHECK(!scratch.is(rs));
2264 r2 = scratch;
2265 li(r2, rt);
2266 offset = shifted_branch_offset(L, false);
2267 bne(rs, r2, offset);
2268 break;
2269 // Signed comparison.
2270 case greater:
2271 if (rt.imm64_ == 0) {
2272 offset = shifted_branch_offset(L, false);
2273 bgtz(rs, offset);
2274 } else {
2275 DCHECK(!scratch.is(rs));
2276 r2 = scratch;
2277 li(r2, rt);
2278 slt(scratch, r2, rs);
2279 offset = shifted_branch_offset(L, false);
2280 bne(scratch, zero_reg, offset);
2281 }
2282 break;
2283 case greater_equal:
2284 if (rt.imm64_ == 0) {
2285 offset = shifted_branch_offset(L, false);
2286 bgez(rs, offset);
2287 } else if (is_int16(rt.imm64_)) {
2288 slti(scratch, rs, rt.imm64_);
2289 offset = shifted_branch_offset(L, false);
2290 beq(scratch, zero_reg, offset);
2291 } else {
2292 DCHECK(!scratch.is(rs));
2293 r2 = scratch;
2294 li(r2, rt);
2295 slt(scratch, rs, r2);
2296 offset = shifted_branch_offset(L, false);
2297 beq(scratch, zero_reg, offset);
2298 }
2299 break;
2300 case less:
2301 if (rt.imm64_ == 0) {
2302 offset = shifted_branch_offset(L, false);
2303 bltz(rs, offset);
2304 } else if (is_int16(rt.imm64_)) {
2305 slti(scratch, rs, rt.imm64_);
2306 offset = shifted_branch_offset(L, false);
2307 bne(scratch, zero_reg, offset);
2308 } else {
2309 DCHECK(!scratch.is(rs));
2310 r2 = scratch;
2311 li(r2, rt);
2312 slt(scratch, rs, r2);
2313 offset = shifted_branch_offset(L, false);
2314 bne(scratch, zero_reg, offset);
2315 }
2316 break;
2317 case less_equal:
2318 if (rt.imm64_ == 0) {
2319 offset = shifted_branch_offset(L, false);
2320 blez(rs, offset);
2321 } else {
2322 DCHECK(!scratch.is(rs));
2323 r2 = scratch;
2324 li(r2, rt);
2325 slt(scratch, r2, rs);
2326 offset = shifted_branch_offset(L, false);
2327 beq(scratch, zero_reg, offset);
2328 }
2329 break;
2330 // Unsigned comparison.
2331 case Ugreater:
2332 if (rt.imm64_ == 0) {
2333 offset = shifted_branch_offset(L, false);
2334 bne(rs, zero_reg, offset);
2335 } else {
2336 DCHECK(!scratch.is(rs));
2337 r2 = scratch;
2338 li(r2, rt);
2339 sltu(scratch, r2, rs);
2340 offset = shifted_branch_offset(L, false);
2341 bne(scratch, zero_reg, offset);
2342 }
2343 break;
2344 case Ugreater_equal:
2345 if (rt.imm64_ == 0) {
2346 offset = shifted_branch_offset(L, false);
2347 bgez(rs, offset);
2348 } else if (is_int16(rt.imm64_)) {
2349 sltiu(scratch, rs, rt.imm64_);
2350 offset = shifted_branch_offset(L, false);
2351 beq(scratch, zero_reg, offset);
2352 } else {
2353 DCHECK(!scratch.is(rs));
2354 r2 = scratch;
2355 li(r2, rt);
2356 sltu(scratch, rs, r2);
2357 offset = shifted_branch_offset(L, false);
2358 beq(scratch, zero_reg, offset);
2359 }
2360 break;
2361 case Uless:
2362 if (rt.imm64_ == 0) {
2363 // No code needs to be emitted.
2364 return;
2365 } else if (is_int16(rt.imm64_)) {
2366 sltiu(scratch, rs, rt.imm64_);
2367 offset = shifted_branch_offset(L, false);
2368 bne(scratch, zero_reg, offset);
2369 } else {
2370 DCHECK(!scratch.is(rs));
2371 r2 = scratch;
2372 li(r2, rt);
2373 sltu(scratch, rs, r2);
2374 offset = shifted_branch_offset(L, false);
2375 bne(scratch, zero_reg, offset);
2376 }
2377 break;
2378 case Uless_equal:
2379 if (rt.imm64_ == 0) {
2380 offset = shifted_branch_offset(L, false);
2381 beq(rs, zero_reg, offset);
2382 } else {
2383 DCHECK(!scratch.is(rs));
2384 r2 = scratch;
2385 li(r2, rt);
2386 sltu(scratch, r2, rs);
2387 offset = shifted_branch_offset(L, false);
2388 beq(scratch, zero_reg, offset);
2389 }
2390 break;
2391 default:
2392 UNREACHABLE();
2393 }
2394 }
2395 // Check that offset could actually hold on an int16_t.
2396 DCHECK(is_int16(offset));
2397 // Emit a nop in the branch delay slot if required.
2398 if (bdslot == PROTECT)
2399 nop();
2400}
2401
2402
2403void MacroAssembler::BranchAndLink(int16_t offset, BranchDelaySlot bdslot) {
2404 BranchAndLinkShort(offset, bdslot);
2405}
2406
2407
2408void MacroAssembler::BranchAndLink(int16_t offset, Condition cond, Register rs,
2409 const Operand& rt,
2410 BranchDelaySlot bdslot) {
2411 BranchAndLinkShort(offset, cond, rs, rt, bdslot);
2412}
2413
2414
2415void MacroAssembler::BranchAndLink(Label* L, BranchDelaySlot bdslot) {
2416 if (L->is_bound()) {
2417 if (is_near(L)) {
2418 BranchAndLinkShort(L, bdslot);
2419 } else {
2420 Jalr(L, bdslot);
2421 }
2422 } else {
2423 if (is_trampoline_emitted()) {
2424 Jalr(L, bdslot);
2425 } else {
2426 BranchAndLinkShort(L, bdslot);
2427 }
2428 }
2429}
2430
2431
2432void MacroAssembler::BranchAndLink(Label* L, Condition cond, Register rs,
2433 const Operand& rt,
2434 BranchDelaySlot bdslot) {
2435 if (L->is_bound()) {
2436 if (is_near(L)) {
2437 BranchAndLinkShort(L, cond, rs, rt, bdslot);
2438 } else {
2439 Label skip;
2440 Condition neg_cond = NegateCondition(cond);
2441 BranchShort(&skip, neg_cond, rs, rt);
2442 Jalr(L, bdslot);
2443 bind(&skip);
2444 }
2445 } else {
2446 if (is_trampoline_emitted()) {
2447 Label skip;
2448 Condition neg_cond = NegateCondition(cond);
2449 BranchShort(&skip, neg_cond, rs, rt);
2450 Jalr(L, bdslot);
2451 bind(&skip);
2452 } else {
2453 BranchAndLinkShort(L, cond, rs, rt, bdslot);
2454 }
2455 }
2456}
2457
2458
2459// We need to use a bgezal or bltzal, but they can't be used directly with the
2460// slt instructions. We could use sub or add instead but we would miss overflow
2461// cases, so we keep slt and add an intermediate third instruction.
2462void MacroAssembler::BranchAndLinkShort(int16_t offset,
2463 BranchDelaySlot bdslot) {
2464 bal(offset);
2465
2466 // Emit a nop in the branch delay slot if required.
2467 if (bdslot == PROTECT)
2468 nop();
2469}
2470
2471
2472void MacroAssembler::BranchAndLinkShort(int16_t offset, Condition cond,
2473 Register rs, const Operand& rt,
2474 BranchDelaySlot bdslot) {
2475 BRANCH_ARGS_CHECK(cond, rs, rt);
2476 Register r2 = no_reg;
2477 Register scratch = at;
2478
2479 if (rt.is_reg()) {
2480 r2 = rt.rm_;
2481 } else if (cond != cc_always) {
2482 r2 = scratch;
2483 li(r2, rt);
2484 }
2485
2486 {
2487 BlockTrampolinePoolScope block_trampoline_pool(this);
2488 switch (cond) {
2489 case cc_always:
2490 bal(offset);
2491 break;
2492 case eq:
2493 bne(rs, r2, 2);
2494 nop();
2495 bal(offset);
2496 break;
2497 case ne:
2498 beq(rs, r2, 2);
2499 nop();
2500 bal(offset);
2501 break;
2502
2503 // Signed comparison.
2504 case greater:
2505 // rs > rt
2506 slt(scratch, r2, rs);
2507 beq(scratch, zero_reg, 2);
2508 nop();
2509 bal(offset);
2510 break;
2511 case greater_equal:
2512 // rs >= rt
2513 slt(scratch, rs, r2);
2514 bne(scratch, zero_reg, 2);
2515 nop();
2516 bal(offset);
2517 break;
2518 case less:
2519 // rs < r2
2520 slt(scratch, rs, r2);
2521 bne(scratch, zero_reg, 2);
2522 nop();
2523 bal(offset);
2524 break;
2525 case less_equal:
2526 // rs <= r2
2527 slt(scratch, r2, rs);
2528 bne(scratch, zero_reg, 2);
2529 nop();
2530 bal(offset);
2531 break;
2532
2533
2534 // Unsigned comparison.
2535 case Ugreater:
2536 // rs > rt
2537 sltu(scratch, r2, rs);
2538 beq(scratch, zero_reg, 2);
2539 nop();
2540 bal(offset);
2541 break;
2542 case Ugreater_equal:
2543 // rs >= rt
2544 sltu(scratch, rs, r2);
2545 bne(scratch, zero_reg, 2);
2546 nop();
2547 bal(offset);
2548 break;
2549 case Uless:
2550 // rs < r2
2551 sltu(scratch, rs, r2);
2552 bne(scratch, zero_reg, 2);
2553 nop();
2554 bal(offset);
2555 break;
2556 case Uless_equal:
2557 // rs <= r2
2558 sltu(scratch, r2, rs);
2559 bne(scratch, zero_reg, 2);
2560 nop();
2561 bal(offset);
2562 break;
2563 default:
2564 UNREACHABLE();
2565 }
2566 }
2567 // Emit a nop in the branch delay slot if required.
2568 if (bdslot == PROTECT)
2569 nop();
2570}
2571
2572
2573void MacroAssembler::BranchAndLinkShort(Label* L, BranchDelaySlot bdslot) {
2574 bal(shifted_branch_offset(L, false));
2575
2576 // Emit a nop in the branch delay slot if required.
2577 if (bdslot == PROTECT)
2578 nop();
2579}
2580
2581
2582void MacroAssembler::BranchAndLinkShort(Label* L, Condition cond, Register rs,
2583 const Operand& rt,
2584 BranchDelaySlot bdslot) {
2585 BRANCH_ARGS_CHECK(cond, rs, rt);
2586
2587 int32_t offset = 0;
2588 Register r2 = no_reg;
2589 Register scratch = at;
2590 if (rt.is_reg()) {
2591 r2 = rt.rm_;
2592 } else if (cond != cc_always) {
2593 r2 = scratch;
2594 li(r2, rt);
2595 }
2596
2597 {
2598 BlockTrampolinePoolScope block_trampoline_pool(this);
2599 switch (cond) {
2600 case cc_always:
2601 offset = shifted_branch_offset(L, false);
2602 bal(offset);
2603 break;
2604 case eq:
2605 bne(rs, r2, 2);
2606 nop();
2607 offset = shifted_branch_offset(L, false);
2608 bal(offset);
2609 break;
2610 case ne:
2611 beq(rs, r2, 2);
2612 nop();
2613 offset = shifted_branch_offset(L, false);
2614 bal(offset);
2615 break;
2616
2617 // Signed comparison.
2618 case greater:
2619 // rs > rt
2620 slt(scratch, r2, rs);
2621 beq(scratch, zero_reg, 2);
2622 nop();
2623 offset = shifted_branch_offset(L, false);
2624 bal(offset);
2625 break;
2626 case greater_equal:
2627 // rs >= rt
2628 slt(scratch, rs, r2);
2629 bne(scratch, zero_reg, 2);
2630 nop();
2631 offset = shifted_branch_offset(L, false);
2632 bal(offset);
2633 break;
2634 case less:
2635 // rs < r2
2636 slt(scratch, rs, r2);
2637 bne(scratch, zero_reg, 2);
2638 nop();
2639 offset = shifted_branch_offset(L, false);
2640 bal(offset);
2641 break;
2642 case less_equal:
2643 // rs <= r2
2644 slt(scratch, r2, rs);
2645 bne(scratch, zero_reg, 2);
2646 nop();
2647 offset = shifted_branch_offset(L, false);
2648 bal(offset);
2649 break;
2650
2651
2652 // Unsigned comparison.
2653 case Ugreater:
2654 // rs > rt
2655 sltu(scratch, r2, rs);
2656 beq(scratch, zero_reg, 2);
2657 nop();
2658 offset = shifted_branch_offset(L, false);
2659 bal(offset);
2660 break;
2661 case Ugreater_equal:
2662 // rs >= rt
2663 sltu(scratch, rs, r2);
2664 bne(scratch, zero_reg, 2);
2665 nop();
2666 offset = shifted_branch_offset(L, false);
2667 bal(offset);
2668 break;
2669 case Uless:
2670 // rs < r2
2671 sltu(scratch, rs, r2);
2672 bne(scratch, zero_reg, 2);
2673 nop();
2674 offset = shifted_branch_offset(L, false);
2675 bal(offset);
2676 break;
2677 case Uless_equal:
2678 // rs <= r2
2679 sltu(scratch, r2, rs);
2680 bne(scratch, zero_reg, 2);
2681 nop();
2682 offset = shifted_branch_offset(L, false);
2683 bal(offset);
2684 break;
2685
2686 default:
2687 UNREACHABLE();
2688 }
2689 }
2690 // Check that offset could actually hold on an int16_t.
2691 DCHECK(is_int16(offset));
2692
2693 // Emit a nop in the branch delay slot if required.
2694 if (bdslot == PROTECT)
2695 nop();
2696}
2697
2698
2699void MacroAssembler::Jump(Register target,
2700 Condition cond,
2701 Register rs,
2702 const Operand& rt,
2703 BranchDelaySlot bd) {
2704 BlockTrampolinePoolScope block_trampoline_pool(this);
2705 if (cond == cc_always) {
2706 jr(target);
2707 } else {
2708 BRANCH_ARGS_CHECK(cond, rs, rt);
2709 Branch(2, NegateCondition(cond), rs, rt);
2710 jr(target);
2711 }
2712 // Emit a nop in the branch delay slot if required.
2713 if (bd == PROTECT)
2714 nop();
2715}
2716
2717
2718void MacroAssembler::Jump(intptr_t target,
2719 RelocInfo::Mode rmode,
2720 Condition cond,
2721 Register rs,
2722 const Operand& rt,
2723 BranchDelaySlot bd) {
2724 Label skip;
2725 if (cond != cc_always) {
2726 Branch(USE_DELAY_SLOT, &skip, NegateCondition(cond), rs, rt);
2727 }
2728 // The first instruction of 'li' may be placed in the delay slot.
2729 // This is not an issue, t9 is expected to be clobbered anyway.
2730 li(t9, Operand(target, rmode));
2731 Jump(t9, al, zero_reg, Operand(zero_reg), bd);
2732 bind(&skip);
2733}
2734
2735
2736void MacroAssembler::Jump(Address target,
2737 RelocInfo::Mode rmode,
2738 Condition cond,
2739 Register rs,
2740 const Operand& rt,
2741 BranchDelaySlot bd) {
2742 DCHECK(!RelocInfo::IsCodeTarget(rmode));
2743 Jump(reinterpret_cast<intptr_t>(target), rmode, cond, rs, rt, bd);
2744}
2745
2746
2747void MacroAssembler::Jump(Handle<Code> code,
2748 RelocInfo::Mode rmode,
2749 Condition cond,
2750 Register rs,
2751 const Operand& rt,
2752 BranchDelaySlot bd) {
2753 DCHECK(RelocInfo::IsCodeTarget(rmode));
2754 AllowDeferredHandleDereference embedding_raw_address;
2755 Jump(reinterpret_cast<intptr_t>(code.location()), rmode, cond, rs, rt, bd);
2756}
2757
2758
2759int MacroAssembler::CallSize(Register target,
2760 Condition cond,
2761 Register rs,
2762 const Operand& rt,
2763 BranchDelaySlot bd) {
2764 int size = 0;
2765
2766 if (cond == cc_always) {
2767 size += 1;
2768 } else {
2769 size += 3;
2770 }
2771
2772 if (bd == PROTECT)
2773 size += 1;
2774
2775 return size * kInstrSize;
2776}
2777
2778
2779// Note: To call gcc-compiled C code on mips, you must call thru t9.
2780void MacroAssembler::Call(Register target,
2781 Condition cond,
2782 Register rs,
2783 const Operand& rt,
2784 BranchDelaySlot bd) {
2785 BlockTrampolinePoolScope block_trampoline_pool(this);
2786 Label start;
2787 bind(&start);
2788 if (cond == cc_always) {
2789 jalr(target);
2790 } else {
2791 BRANCH_ARGS_CHECK(cond, rs, rt);
2792 Branch(2, NegateCondition(cond), rs, rt);
2793 jalr(target);
2794 }
2795 // Emit a nop in the branch delay slot if required.
2796 if (bd == PROTECT)
2797 nop();
2798
2799 DCHECK_EQ(CallSize(target, cond, rs, rt, bd),
2800 SizeOfCodeGeneratedSince(&start));
2801}
2802
2803
2804int MacroAssembler::CallSize(Address target,
2805 RelocInfo::Mode rmode,
2806 Condition cond,
2807 Register rs,
2808 const Operand& rt,
2809 BranchDelaySlot bd) {
2810 int size = CallSize(t9, cond, rs, rt, bd);
2811 return size + 4 * kInstrSize;
2812}
2813
2814
2815void MacroAssembler::Call(Address target,
2816 RelocInfo::Mode rmode,
2817 Condition cond,
2818 Register rs,
2819 const Operand& rt,
2820 BranchDelaySlot bd) {
2821 BlockTrampolinePoolScope block_trampoline_pool(this);
2822 Label start;
2823 bind(&start);
2824 int64_t target_int = reinterpret_cast<int64_t>(target);
2825 // Must record previous source positions before the
2826 // li() generates a new code target.
2827 positions_recorder()->WriteRecordedPositions();
2828 li(t9, Operand(target_int, rmode), ADDRESS_LOAD);
2829 Call(t9, cond, rs, rt, bd);
2830 DCHECK_EQ(CallSize(target, rmode, cond, rs, rt, bd),
2831 SizeOfCodeGeneratedSince(&start));
2832}
2833
2834
2835int MacroAssembler::CallSize(Handle<Code> code,
2836 RelocInfo::Mode rmode,
2837 TypeFeedbackId ast_id,
2838 Condition cond,
2839 Register rs,
2840 const Operand& rt,
2841 BranchDelaySlot bd) {
2842 AllowDeferredHandleDereference using_raw_address;
2843 return CallSize(reinterpret_cast<Address>(code.location()),
2844 rmode, cond, rs, rt, bd);
2845}
2846
2847
2848void MacroAssembler::Call(Handle<Code> code,
2849 RelocInfo::Mode rmode,
2850 TypeFeedbackId ast_id,
2851 Condition cond,
2852 Register rs,
2853 const Operand& rt,
2854 BranchDelaySlot bd) {
2855 BlockTrampolinePoolScope block_trampoline_pool(this);
2856 Label start;
2857 bind(&start);
2858 DCHECK(RelocInfo::IsCodeTarget(rmode));
2859 if (rmode == RelocInfo::CODE_TARGET && !ast_id.IsNone()) {
2860 SetRecordedAstId(ast_id);
2861 rmode = RelocInfo::CODE_TARGET_WITH_ID;
2862 }
2863 AllowDeferredHandleDereference embedding_raw_address;
2864 Call(reinterpret_cast<Address>(code.location()), rmode, cond, rs, rt, bd);
2865 DCHECK_EQ(CallSize(code, rmode, ast_id, cond, rs, rt, bd),
2866 SizeOfCodeGeneratedSince(&start));
2867}
2868
2869
2870void MacroAssembler::Ret(Condition cond,
2871 Register rs,
2872 const Operand& rt,
2873 BranchDelaySlot bd) {
2874 Jump(ra, cond, rs, rt, bd);
2875}
2876
2877
2878void MacroAssembler::J(Label* L, BranchDelaySlot bdslot) {
2879 BlockTrampolinePoolScope block_trampoline_pool(this);
2880
2881 uint64_t imm28;
2882 imm28 = jump_address(L);
2883 imm28 &= kImm28Mask;
2884 { BlockGrowBufferScope block_buf_growth(this);
2885 // Buffer growth (and relocation) must be blocked for internal references
2886 // until associated instructions are emitted and available to be patched.
2887 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2888 j(imm28);
2889 }
2890 // Emit a nop in the branch delay slot if required.
2891 if (bdslot == PROTECT)
2892 nop();
2893}
2894
2895
2896void MacroAssembler::Jr(Label* L, BranchDelaySlot bdslot) {
2897 BlockTrampolinePoolScope block_trampoline_pool(this);
2898
2899 uint64_t imm64;
2900 imm64 = jump_address(L);
2901 { BlockGrowBufferScope block_buf_growth(this);
2902 // Buffer growth (and relocation) must be blocked for internal references
2903 // until associated instructions are emitted and available to be patched.
2904 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2905 li(at, Operand(imm64), ADDRESS_LOAD);
2906 }
2907 jr(at);
2908
2909 // Emit a nop in the branch delay slot if required.
2910 if (bdslot == PROTECT)
2911 nop();
2912}
2913
2914
2915void MacroAssembler::Jalr(Label* L, BranchDelaySlot bdslot) {
2916 BlockTrampolinePoolScope block_trampoline_pool(this);
2917
2918 uint64_t imm64;
2919 imm64 = jump_address(L);
2920 { BlockGrowBufferScope block_buf_growth(this);
2921 // Buffer growth (and relocation) must be blocked for internal references
2922 // until associated instructions are emitted and available to be patched.
2923 RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE);
2924 li(at, Operand(imm64), ADDRESS_LOAD);
2925 }
2926 jalr(at);
2927
2928 // Emit a nop in the branch delay slot if required.
2929 if (bdslot == PROTECT)
2930 nop();
2931}
2932
2933
2934void MacroAssembler::DropAndRet(int drop) {
2935 Ret(USE_DELAY_SLOT);
2936 daddiu(sp, sp, drop * kPointerSize);
2937}
2938
2939void MacroAssembler::DropAndRet(int drop,
2940 Condition cond,
2941 Register r1,
2942 const Operand& r2) {
2943 // Both Drop and Ret need to be conditional.
2944 Label skip;
2945 if (cond != cc_always) {
2946 Branch(&skip, NegateCondition(cond), r1, r2);
2947 }
2948
2949 Drop(drop);
2950 Ret();
2951
2952 if (cond != cc_always) {
2953 bind(&skip);
2954 }
2955}
2956
2957
2958void MacroAssembler::Drop(int count,
2959 Condition cond,
2960 Register reg,
2961 const Operand& op) {
2962 if (count <= 0) {
2963 return;
2964 }
2965
2966 Label skip;
2967
2968 if (cond != al) {
2969 Branch(&skip, NegateCondition(cond), reg, op);
2970 }
2971
2972 daddiu(sp, sp, count * kPointerSize);
2973
2974 if (cond != al) {
2975 bind(&skip);
2976 }
2977}
2978
2979
2980
2981void MacroAssembler::Swap(Register reg1,
2982 Register reg2,
2983 Register scratch) {
2984 if (scratch.is(no_reg)) {
2985 Xor(reg1, reg1, Operand(reg2));
2986 Xor(reg2, reg2, Operand(reg1));
2987 Xor(reg1, reg1, Operand(reg2));
2988 } else {
2989 mov(scratch, reg1);
2990 mov(reg1, reg2);
2991 mov(reg2, scratch);
2992 }
2993}
2994
2995
2996void MacroAssembler::Call(Label* target) {
2997 BranchAndLink(target);
2998}
2999
3000
3001void MacroAssembler::Push(Handle<Object> handle) {
3002 li(at, Operand(handle));
3003 push(at);
3004}
3005
3006
3007void MacroAssembler::PushRegisterAsTwoSmis(Register src, Register scratch) {
3008 DCHECK(!src.is(scratch));
3009 mov(scratch, src);
3010 dsrl32(src, src, 0);
3011 dsll32(src, src, 0);
3012 push(src);
3013 dsll32(scratch, scratch, 0);
3014 push(scratch);
3015}
3016
3017
3018void MacroAssembler::PopRegisterAsTwoSmis(Register dst, Register scratch) {
3019 DCHECK(!dst.is(scratch));
3020 pop(scratch);
3021 dsrl32(scratch, scratch, 0);
3022 pop(dst);
3023 dsrl32(dst, dst, 0);
3024 dsll32(dst, dst, 0);
3025 or_(dst, dst, scratch);
3026}
3027
3028
3029void MacroAssembler::DebugBreak() {
3030 PrepareCEntryArgs(0);
3031 PrepareCEntryFunction(ExternalReference(Runtime::kDebugBreak, isolate()));
3032 CEntryStub ces(isolate(), 1);
3033 DCHECK(AllowThisStubCall(&ces));
3034 Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
3035}
3036
3037
3038// ---------------------------------------------------------------------------
3039// Exception handling.
3040
3041void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
3042 int handler_index) {
3043 // Adjust this code if not the case.
3044 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
3045 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
3046 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
3047 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
3048 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
3049 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
3050
3051 // For the JSEntry handler, we must preserve a0-a3 and s0.
3052 // a5-a7 are available. We will build up the handler from the bottom by
3053 // pushing on the stack.
3054 // Set up the code object (a5) and the state (a6) for pushing.
3055 unsigned state =
3056 StackHandler::IndexField::encode(handler_index) |
3057 StackHandler::KindField::encode(kind);
3058 li(a5, Operand(CodeObject()), CONSTANT_SIZE);
3059 li(a6, Operand(state));
3060
3061 // Push the frame pointer, context, state, and code object.
3062 if (kind == StackHandler::JS_ENTRY) {
3063 DCHECK_EQ(Smi::FromInt(0), 0);
3064 // The second zero_reg indicates no context.
3065 // The first zero_reg is the NULL frame pointer.
3066 // The operands are reversed to match the order of MultiPush/Pop.
3067 Push(zero_reg, zero_reg, a6, a5);
3068 } else {
3069 MultiPush(a5.bit() | a6.bit() | cp.bit() | fp.bit());
3070 }
3071
3072 // Link the current handler as the next handler.
3073 li(a6, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
3074 ld(a5, MemOperand(a6));
3075 push(a5);
3076 // Set this new handler as the current one.
3077 sd(sp, MemOperand(a6));
3078}
3079
3080
3081void MacroAssembler::PopTryHandler() {
3082 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
3083 pop(a1);
3084 Daddu(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
3085 li(at, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
3086 sd(a1, MemOperand(at));
3087}
3088
3089
3090void MacroAssembler::JumpToHandlerEntry() {
3091 // Compute the handler entry address and jump to it. The handler table is
3092 // a fixed array of (smi-tagged) code offsets.
3093 // v0 = exception, a1 = code object, a2 = state.
3094 Uld(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));
3095 Daddu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3096 dsrl(a2, a2, StackHandler::kKindWidth); // Handler index.
3097 dsll(a2, a2, kPointerSizeLog2);
3098 Daddu(a2, a3, a2);
3099 ld(a2, MemOperand(a2)); // Smi-tagged offset.
3100 Daddu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
3101 dsra32(t9, a2, 0);
3102 Daddu(t9, t9, a1);
3103 Jump(t9); // Jump.
3104}
3105
3106
3107void MacroAssembler::Throw(Register value) {
3108 // Adjust this code if not the case.
3109 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
3110 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
3111 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
3112 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
3113 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
3114 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
3115
3116 // The exception is expected in v0.
3117 Move(v0, value);
3118
3119 // Drop the stack pointer to the top of the top handler.
3120 li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
3121 isolate())));
3122 ld(sp, MemOperand(a3));
3123
3124 // Restore the next handler.
3125 pop(a2);
3126 sd(a2, MemOperand(a3));
3127
3128 // Get the code object (a1) and state (a2). Restore the context and frame
3129 // pointer.
3130 MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
3131
3132 // If the handler is a JS frame, restore the context to the frame.
3133 // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
3134 // or cp.
3135 Label done;
3136 Branch(&done, eq, cp, Operand(zero_reg));
3137 sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
3138 bind(&done);
3139
3140 JumpToHandlerEntry();
3141}
3142
3143
3144void MacroAssembler::ThrowUncatchable(Register value) {
3145 // Adjust this code if not the case.
3146 STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
3147 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
3148 STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
3149 STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
3150 STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
3151 STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
3152
3153 // The exception is expected in v0.
3154 if (!value.is(v0)) {
3155 mov(v0, value);
3156 }
3157 // Drop the stack pointer to the top of the top stack handler.
3158 li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
3159 ld(sp, MemOperand(a3));
3160
3161 // Unwind the handlers until the ENTRY handler is found.
3162 Label fetch_next, check_kind;
3163 jmp(&check_kind);
3164 bind(&fetch_next);
3165 ld(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
3166
3167 bind(&check_kind);
3168 STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
3169 ld(a2, MemOperand(sp, StackHandlerConstants::kStateOffset));
3170 And(a2, a2, Operand(StackHandler::KindField::kMask));
3171 Branch(&fetch_next, ne, a2, Operand(zero_reg));
3172
3173 // Set the top handler address to next handler past the top ENTRY handler.
3174 pop(a2);
3175 sd(a2, MemOperand(a3));
3176
3177 // Get the code object (a1) and state (a2). Clear the context and frame
3178 // pointer (0 was saved in the handler).
3179 MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
3180
3181 JumpToHandlerEntry();
3182}
3183
3184
3185void MacroAssembler::Allocate(int object_size,
3186 Register result,
3187 Register scratch1,
3188 Register scratch2,
3189 Label* gc_required,
3190 AllocationFlags flags) {
3191 DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
3192 if (!FLAG_inline_new) {
3193 if (emit_debug_code()) {
3194 // Trash the registers to simulate an allocation failure.
3195 li(result, 0x7091);
3196 li(scratch1, 0x7191);
3197 li(scratch2, 0x7291);
3198 }
3199 jmp(gc_required);
3200 return;
3201 }
3202
3203 DCHECK(!result.is(scratch1));
3204 DCHECK(!result.is(scratch2));
3205 DCHECK(!scratch1.is(scratch2));
3206 DCHECK(!scratch1.is(t9));
3207 DCHECK(!scratch2.is(t9));
3208 DCHECK(!result.is(t9));
3209
3210 // Make object size into bytes.
3211 if ((flags & SIZE_IN_WORDS) != 0) {
3212 object_size *= kPointerSize;
3213 }
3214 DCHECK(0 == (object_size & kObjectAlignmentMask));
3215
3216 // Check relative positions of allocation top and limit addresses.
3217 // ARM adds additional checks to make sure the ldm instruction can be
3218 // used. On MIPS we don't have ldm so we don't need additional checks either.
3219 ExternalReference allocation_top =
3220 AllocationUtils::GetAllocationTopReference(isolate(), flags);
3221 ExternalReference allocation_limit =
3222 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
3223
3224 intptr_t top =
3225 reinterpret_cast<intptr_t>(allocation_top.address());
3226 intptr_t limit =
3227 reinterpret_cast<intptr_t>(allocation_limit.address());
3228 DCHECK((limit - top) == kPointerSize);
3229
3230 // Set up allocation top address and object size registers.
3231 Register topaddr = scratch1;
3232 li(topaddr, Operand(allocation_top));
3233
3234 // This code stores a temporary value in t9.
3235 if ((flags & RESULT_CONTAINS_TOP) == 0) {
3236 // Load allocation top into result and allocation limit into t9.
3237 ld(result, MemOperand(topaddr));
3238 ld(t9, MemOperand(topaddr, kPointerSize));
3239 } else {
3240 if (emit_debug_code()) {
3241 // Assert that result actually contains top on entry. t9 is used
3242 // immediately below so this use of t9 does not cause difference with
3243 // respect to register content between debug and release mode.
3244 ld(t9, MemOperand(topaddr));
3245 Check(eq, kUnexpectedAllocationTop, result, Operand(t9));
3246 }
3247 // Load allocation limit into t9. Result already contains allocation top.
3248 ld(t9, MemOperand(topaddr, limit - top));
3249 }
3250
3251 DCHECK(kPointerSize == kDoubleSize);
3252 if (emit_debug_code()) {
3253 And(at, result, Operand(kDoubleAlignmentMask));
3254 Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
3255 }
3256
3257 // Calculate new top and bail out if new space is exhausted. Use result
3258 // to calculate the new top.
3259 Daddu(scratch2, result, Operand(object_size));
3260 Branch(gc_required, Ugreater, scratch2, Operand(t9));
3261 sd(scratch2, MemOperand(topaddr));
3262
3263 // Tag object if requested.
3264 if ((flags & TAG_OBJECT) != 0) {
3265 Daddu(result, result, Operand(kHeapObjectTag));
3266 }
3267}
3268
3269
3270void MacroAssembler::Allocate(Register object_size,
3271 Register result,
3272 Register scratch1,
3273 Register scratch2,
3274 Label* gc_required,
3275 AllocationFlags flags) {
3276 if (!FLAG_inline_new) {
3277 if (emit_debug_code()) {
3278 // Trash the registers to simulate an allocation failure.
3279 li(result, 0x7091);
3280 li(scratch1, 0x7191);
3281 li(scratch2, 0x7291);
3282 }
3283 jmp(gc_required);
3284 return;
3285 }
3286
3287 DCHECK(!result.is(scratch1));
3288 DCHECK(!result.is(scratch2));
3289 DCHECK(!scratch1.is(scratch2));
3290 DCHECK(!object_size.is(t9));
3291 DCHECK(!scratch1.is(t9) && !scratch2.is(t9) && !result.is(t9));
3292
3293 // Check relative positions of allocation top and limit addresses.
3294 // ARM adds additional checks to make sure the ldm instruction can be
3295 // used. On MIPS we don't have ldm so we don't need additional checks either.
3296 ExternalReference allocation_top =
3297 AllocationUtils::GetAllocationTopReference(isolate(), flags);
3298 ExternalReference allocation_limit =
3299 AllocationUtils::GetAllocationLimitReference(isolate(), flags);
3300 intptr_t top =
3301 reinterpret_cast<intptr_t>(allocation_top.address());
3302 intptr_t limit =
3303 reinterpret_cast<intptr_t>(allocation_limit.address());
3304 DCHECK((limit - top) == kPointerSize);
3305
3306 // Set up allocation top address and object size registers.
3307 Register topaddr = scratch1;
3308 li(topaddr, Operand(allocation_top));
3309
3310 // This code stores a temporary value in t9.
3311 if ((flags & RESULT_CONTAINS_TOP) == 0) {
3312 // Load allocation top into result and allocation limit into t9.
3313 ld(result, MemOperand(topaddr));
3314 ld(t9, MemOperand(topaddr, kPointerSize));
3315 } else {
3316 if (emit_debug_code()) {
3317 // Assert that result actually contains top on entry. t9 is used
3318 // immediately below so this use of t9 does not cause difference with
3319 // respect to register content between debug and release mode.
3320 ld(t9, MemOperand(topaddr));
3321 Check(eq, kUnexpectedAllocationTop, result, Operand(t9));
3322 }
3323 // Load allocation limit into t9. Result already contains allocation top.
3324 ld(t9, MemOperand(topaddr, limit - top));
3325 }
3326
3327 DCHECK(kPointerSize == kDoubleSize);
3328 if (emit_debug_code()) {
3329 And(at, result, Operand(kDoubleAlignmentMask));
3330 Check(eq, kAllocationIsNotDoubleAligned, at, Operand(zero_reg));
3331 }
3332
3333 // Calculate new top and bail out if new space is exhausted. Use result
3334 // to calculate the new top. Object size may be in words so a shift is
3335 // required to get the number of bytes.
3336 if ((flags & SIZE_IN_WORDS) != 0) {
3337 dsll(scratch2, object_size, kPointerSizeLog2);
3338 Daddu(scratch2, result, scratch2);
3339 } else {
3340 Daddu(scratch2, result, Operand(object_size));
3341 }
3342 Branch(gc_required, Ugreater, scratch2, Operand(t9));
3343
3344 // Update allocation top. result temporarily holds the new top.
3345 if (emit_debug_code()) {
3346 And(t9, scratch2, Operand(kObjectAlignmentMask));
3347 Check(eq, kUnalignedAllocationInNewSpace, t9, Operand(zero_reg));
3348 }
3349 sd(scratch2, MemOperand(topaddr));
3350
3351 // Tag object if requested.
3352 if ((flags & TAG_OBJECT) != 0) {
3353 Daddu(result, result, Operand(kHeapObjectTag));
3354 }
3355}
3356
3357
3358void MacroAssembler::UndoAllocationInNewSpace(Register object,
3359 Register scratch) {
3360 ExternalReference new_space_allocation_top =
3361 ExternalReference::new_space_allocation_top_address(isolate());
3362
3363 // Make sure the object has no tag before resetting top.
3364 And(object, object, Operand(~kHeapObjectTagMask));
3365#ifdef DEBUG
3366 // Check that the object un-allocated is below the current top.
3367 li(scratch, Operand(new_space_allocation_top));
3368 ld(scratch, MemOperand(scratch));
3369 Check(less, kUndoAllocationOfNonAllocatedMemory,
3370 object, Operand(scratch));
3371#endif
3372 // Write the address of the object to un-allocate as the current top.
3373 li(scratch, Operand(new_space_allocation_top));
3374 sd(object, MemOperand(scratch));
3375}
3376
3377
3378void MacroAssembler::AllocateTwoByteString(Register result,
3379 Register length,
3380 Register scratch1,
3381 Register scratch2,
3382 Register scratch3,
3383 Label* gc_required) {
3384 // Calculate the number of bytes needed for the characters in the string while
3385 // observing object alignment.
3386 DCHECK((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
3387 dsll(scratch1, length, 1); // Length in bytes, not chars.
3388 daddiu(scratch1, scratch1,
3389 kObjectAlignmentMask + SeqTwoByteString::kHeaderSize);
3390 And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
3391
3392 // Allocate two-byte string in new space.
3393 Allocate(scratch1,
3394 result,
3395 scratch2,
3396 scratch3,
3397 gc_required,
3398 TAG_OBJECT);
3399
3400 // Set the map, length and hash field.
3401 InitializeNewString(result,
3402 length,
3403 Heap::kStringMapRootIndex,
3404 scratch1,
3405 scratch2);
3406}
3407
3408
3409void MacroAssembler::AllocateOneByteString(Register result, Register length,
3410 Register scratch1, Register scratch2,
3411 Register scratch3,
3412 Label* gc_required) {
3413 // Calculate the number of bytes needed for the characters in the string
3414 // while observing object alignment.
3415 DCHECK((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
3416 DCHECK(kCharSize == 1);
3417 daddiu(scratch1, length,
3418 kObjectAlignmentMask + SeqOneByteString::kHeaderSize);
3419 And(scratch1, scratch1, Operand(~kObjectAlignmentMask));
3420
3421 // Allocate one-byte string in new space.
3422 Allocate(scratch1,
3423 result,
3424 scratch2,
3425 scratch3,
3426 gc_required,
3427 TAG_OBJECT);
3428
3429 // Set the map, length and hash field.
3430 InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
3431 scratch1, scratch2);
3432}
3433
3434
3435void MacroAssembler::AllocateTwoByteConsString(Register result,
3436 Register length,
3437 Register scratch1,
3438 Register scratch2,
3439 Label* gc_required) {
3440 Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
3441 TAG_OBJECT);
3442 InitializeNewString(result,
3443 length,
3444 Heap::kConsStringMapRootIndex,
3445 scratch1,
3446 scratch2);
3447}
3448
3449
3450void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
3451 Register scratch1,
3452 Register scratch2,
3453 Label* gc_required) {
3454 Allocate(ConsString::kSize,
3455 result,
3456 scratch1,
3457 scratch2,
3458 gc_required,
3459 TAG_OBJECT);
3460
3461 InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
3462 scratch1, scratch2);
3463}
3464
3465
3466void MacroAssembler::AllocateTwoByteSlicedString(Register result,
3467 Register length,
3468 Register scratch1,
3469 Register scratch2,
3470 Label* gc_required) {
3471 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
3472 TAG_OBJECT);
3473
3474 InitializeNewString(result,
3475 length,
3476 Heap::kSlicedStringMapRootIndex,
3477 scratch1,
3478 scratch2);
3479}
3480
3481
3482void MacroAssembler::AllocateOneByteSlicedString(Register result,
3483 Register length,
3484 Register scratch1,
3485 Register scratch2,
3486 Label* gc_required) {
3487 Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
3488 TAG_OBJECT);
3489
3490 InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
3491 scratch1, scratch2);
3492}
3493
3494
3495void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register reg,
3496 Label* not_unique_name) {
3497 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0);
3498 Label succeed;
3499 And(at, reg, Operand(kIsNotStringMask | kIsNotInternalizedMask));
3500 Branch(&succeed, eq, at, Operand(zero_reg));
3501 Branch(not_unique_name, ne, reg, Operand(SYMBOL_TYPE));
3502
3503 bind(&succeed);
3504}
3505
3506
3507// Allocates a heap number or jumps to the label if the young space is full and
3508// a scavenge is needed.
3509void MacroAssembler::AllocateHeapNumber(Register result,
3510 Register scratch1,
3511 Register scratch2,
3512 Register heap_number_map,
3513 Label* need_gc,
3514 TaggingMode tagging_mode,
3515 MutableMode mode) {
3516 // Allocate an object in the heap for the heap number and tag it as a heap
3517 // object.
3518 Allocate(HeapNumber::kSize, result, scratch1, scratch2, need_gc,
3519 tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);
3520
3521 Heap::RootListIndex map_index = mode == MUTABLE
3522 ? Heap::kMutableHeapNumberMapRootIndex
3523 : Heap::kHeapNumberMapRootIndex;
3524 AssertIsRoot(heap_number_map, map_index);
3525
3526 // Store heap number map in the allocated object.
3527 if (tagging_mode == TAG_RESULT) {
3528 sd(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
3529 } else {
3530 sd(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
3531 }
3532}
3533
3534
3535void MacroAssembler::AllocateHeapNumberWithValue(Register result,
3536 FPURegister value,
3537 Register scratch1,
3538 Register scratch2,
3539 Label* gc_required) {
3540 LoadRoot(t8, Heap::kHeapNumberMapRootIndex);
3541 AllocateHeapNumber(result, scratch1, scratch2, t8, gc_required);
3542 sdc1(value, FieldMemOperand(result, HeapNumber::kValueOffset));
3543}
3544
3545
3546// Copies a fixed number of fields of heap objects from src to dst.
3547void MacroAssembler::CopyFields(Register dst,
3548 Register src,
3549 RegList temps,
3550 int field_count) {
3551 DCHECK((temps & dst.bit()) == 0);
3552 DCHECK((temps & src.bit()) == 0);
3553 // Primitive implementation using only one temporary register.
3554
3555 Register tmp = no_reg;
3556 // Find a temp register in temps list.
3557 for (int i = 0; i < kNumRegisters; i++) {
3558 if ((temps & (1 << i)) != 0) {
3559 tmp.code_ = i;
3560 break;
3561 }
3562 }
3563 DCHECK(!tmp.is(no_reg));
3564
3565 for (int i = 0; i < field_count; i++) {
3566 ld(tmp, FieldMemOperand(src, i * kPointerSize));
3567 sd(tmp, FieldMemOperand(dst, i * kPointerSize));
3568 }
3569}
3570
3571
3572void MacroAssembler::CopyBytes(Register src,
3573 Register dst,
3574 Register length,
3575 Register scratch) {
3576 Label align_loop_1, word_loop, byte_loop, byte_loop_1, done;
3577
3578 // Align src before copying in word size chunks.
3579 Branch(&byte_loop, le, length, Operand(kPointerSize));
3580 bind(&align_loop_1);
3581 And(scratch, src, kPointerSize - 1);
3582 Branch(&word_loop, eq, scratch, Operand(zero_reg));
3583 lbu(scratch, MemOperand(src));
3584 Daddu(src, src, 1);
3585 sb(scratch, MemOperand(dst));
3586 Daddu(dst, dst, 1);
3587 Dsubu(length, length, Operand(1));
3588 Branch(&align_loop_1, ne, length, Operand(zero_reg));
3589
3590 // Copy bytes in word size chunks.
3591 bind(&word_loop);
3592 if (emit_debug_code()) {
3593 And(scratch, src, kPointerSize - 1);
3594 Assert(eq, kExpectingAlignmentForCopyBytes,
3595 scratch, Operand(zero_reg));
3596 }
3597 Branch(&byte_loop, lt, length, Operand(kPointerSize));
3598 ld(scratch, MemOperand(src));
3599 Daddu(src, src, kPointerSize);
3600
3601 // TODO(kalmard) check if this can be optimized to use sw in most cases.
3602 // Can't use unaligned access - copy byte by byte.
3603 sb(scratch, MemOperand(dst, 0));
3604 dsrl(scratch, scratch, 8);
3605 sb(scratch, MemOperand(dst, 1));
3606 dsrl(scratch, scratch, 8);
3607 sb(scratch, MemOperand(dst, 2));
3608 dsrl(scratch, scratch, 8);
3609 sb(scratch, MemOperand(dst, 3));
3610 dsrl(scratch, scratch, 8);
3611 sb(scratch, MemOperand(dst, 4));
3612 dsrl(scratch, scratch, 8);
3613 sb(scratch, MemOperand(dst, 5));
3614 dsrl(scratch, scratch, 8);
3615 sb(scratch, MemOperand(dst, 6));
3616 dsrl(scratch, scratch, 8);
3617 sb(scratch, MemOperand(dst, 7));
3618 Daddu(dst, dst, 8);
3619
3620 Dsubu(length, length, Operand(kPointerSize));
3621 Branch(&word_loop);
3622
3623 // Copy the last bytes if any left.
3624 bind(&byte_loop);
3625 Branch(&done, eq, length, Operand(zero_reg));
3626 bind(&byte_loop_1);
3627 lbu(scratch, MemOperand(src));
3628 Daddu(src, src, 1);
3629 sb(scratch, MemOperand(dst));
3630 Daddu(dst, dst, 1);
3631 Dsubu(length, length, Operand(1));
3632 Branch(&byte_loop_1, ne, length, Operand(zero_reg));
3633 bind(&done);
3634}
3635
3636
3637void MacroAssembler::InitializeFieldsWithFiller(Register start_offset,
3638 Register end_offset,
3639 Register filler) {
3640 Label loop, entry;
3641 Branch(&entry);
3642 bind(&loop);
3643 sd(filler, MemOperand(start_offset));
3644 Daddu(start_offset, start_offset, kPointerSize);
3645 bind(&entry);
3646 Branch(&loop, lt, start_offset, Operand(end_offset));
3647}
3648
3649
3650void MacroAssembler::CheckFastElements(Register map,
3651 Register scratch,
3652 Label* fail) {
3653 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
3654 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
3655 STATIC_ASSERT(FAST_ELEMENTS == 2);
3656 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
3657 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
3658 Branch(fail, hi, scratch,
3659 Operand(Map::kMaximumBitField2FastHoleyElementValue));
3660}
3661
3662
3663void MacroAssembler::CheckFastObjectElements(Register map,
3664 Register scratch,
3665 Label* fail) {
3666 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
3667 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
3668 STATIC_ASSERT(FAST_ELEMENTS == 2);
3669 STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
3670 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
3671 Branch(fail, ls, scratch,
3672 Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
3673 Branch(fail, hi, scratch,
3674 Operand(Map::kMaximumBitField2FastHoleyElementValue));
3675}
3676
3677
3678void MacroAssembler::CheckFastSmiElements(Register map,
3679 Register scratch,
3680 Label* fail) {
3681 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
3682 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
3683 lbu(scratch, FieldMemOperand(map, Map::kBitField2Offset));
3684 Branch(fail, hi, scratch,
3685 Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
3686}
3687
3688
3689void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
3690 Register key_reg,
3691 Register elements_reg,
3692 Register scratch1,
3693 Register scratch2,
3694 Register scratch3,
3695 Label* fail,
3696 int elements_offset) {
3697 Label smi_value, maybe_nan, have_double_value, is_nan, done;
3698 Register mantissa_reg = scratch2;
3699 Register exponent_reg = scratch3;
3700
3701 // Handle smi values specially.
3702 JumpIfSmi(value_reg, &smi_value);
3703
3704 // Ensure that the object is a heap number
3705 CheckMap(value_reg,
3706 scratch1,
3707 Heap::kHeapNumberMapRootIndex,
3708 fail,
3709 DONT_DO_SMI_CHECK);
3710
3711 // Check for nan: all NaN values have a value greater (signed) than 0x7ff00000
3712 // in the exponent.
3713 li(scratch1, Operand(kNaNOrInfinityLowerBoundUpper32));
3714 lw(exponent_reg, FieldMemOperand(value_reg, HeapNumber::kExponentOffset));
3715 Branch(&maybe_nan, ge, exponent_reg, Operand(scratch1));
3716
3717 lwu(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
3718
3719 bind(&have_double_value);
3720 // dsll(scratch1, key_reg, kDoubleSizeLog2 - kSmiTagSize);
3721 dsra(scratch1, key_reg, 32 - kDoubleSizeLog2);
3722 Daddu(scratch1, scratch1, elements_reg);
3723 sw(mantissa_reg, FieldMemOperand(
3724 scratch1, FixedDoubleArray::kHeaderSize - elements_offset));
3725 uint32_t offset = FixedDoubleArray::kHeaderSize - elements_offset +
3726 sizeof(kHoleNanLower32);
3727 sw(exponent_reg, FieldMemOperand(scratch1, offset));
3728 jmp(&done);
3729
3730 bind(&maybe_nan);
3731 // Could be NaN, Infinity or -Infinity. If fraction is not zero, it's NaN,
3732 // otherwise it's Infinity or -Infinity, and the non-NaN code path applies.
3733 lw(mantissa_reg, FieldMemOperand(value_reg, HeapNumber::kMantissaOffset));
3734 Branch(&have_double_value, eq, mantissa_reg, Operand(zero_reg));
3735 bind(&is_nan);
3736 // Load canonical NaN for storing into the double array.
3737 LoadRoot(at, Heap::kNanValueRootIndex);
3738 lw(mantissa_reg, FieldMemOperand(at, HeapNumber::kMantissaOffset));
3739 lw(exponent_reg, FieldMemOperand(at, HeapNumber::kExponentOffset));
3740 jmp(&have_double_value);
3741
3742 bind(&smi_value);
3743 Daddu(scratch1, elements_reg,
3744 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag -
3745 elements_offset));
3746 // dsll(scratch2, key_reg, kDoubleSizeLog2 - kSmiTagSize);
3747 dsra(scratch2, key_reg, 32 - kDoubleSizeLog2);
3748 Daddu(scratch1, scratch1, scratch2);
3749 // scratch1 is now effective address of the double element
3750
3751 Register untagged_value = elements_reg;
3752 SmiUntag(untagged_value, value_reg);
3753 mtc1(untagged_value, f2);
3754 cvt_d_w(f0, f2);
3755 sdc1(f0, MemOperand(scratch1, 0));
3756 bind(&done);
3757}
3758
3759
3760void MacroAssembler::CompareMapAndBranch(Register obj,
3761 Register scratch,
3762 Handle<Map> map,
3763 Label* early_success,
3764 Condition cond,
3765 Label* branch_to) {
3766 ld(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3767 CompareMapAndBranch(scratch, map, early_success, cond, branch_to);
3768}
3769
3770
3771void MacroAssembler::CompareMapAndBranch(Register obj_map,
3772 Handle<Map> map,
3773 Label* early_success,
3774 Condition cond,
3775 Label* branch_to) {
3776 Branch(branch_to, cond, obj_map, Operand(map));
3777}
3778
3779
3780void MacroAssembler::CheckMap(Register obj,
3781 Register scratch,
3782 Handle<Map> map,
3783 Label* fail,
3784 SmiCheckType smi_check_type) {
3785 if (smi_check_type == DO_SMI_CHECK) {
3786 JumpIfSmi(obj, fail);
3787 }
3788 Label success;
3789 CompareMapAndBranch(obj, scratch, map, &success, ne, fail);
3790 bind(&success);
3791}
3792
3793
3794void MacroAssembler::DispatchMap(Register obj,
3795 Register scratch,
3796 Handle<Map> map,
3797 Handle<Code> success,
3798 SmiCheckType smi_check_type) {
3799 Label fail;
3800 if (smi_check_type == DO_SMI_CHECK) {
3801 JumpIfSmi(obj, &fail);
3802 }
3803 ld(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3804 Jump(success, RelocInfo::CODE_TARGET, eq, scratch, Operand(map));
3805 bind(&fail);
3806}
3807
3808
3809void MacroAssembler::CheckMap(Register obj,
3810 Register scratch,
3811 Heap::RootListIndex index,
3812 Label* fail,
3813 SmiCheckType smi_check_type) {
3814 if (smi_check_type == DO_SMI_CHECK) {
3815 JumpIfSmi(obj, fail);
3816 }
3817 ld(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
3818 LoadRoot(at, index);
3819 Branch(fail, ne, scratch, Operand(at));
3820}
3821
3822
3823void MacroAssembler::MovFromFloatResult(const DoubleRegister dst) {
3824 if (IsMipsSoftFloatABI) {
3825 Move(dst, v0, v1);
3826 } else {
3827 Move(dst, f0); // Reg f0 is o32 ABI FP return value.
3828 }
3829}
3830
3831
3832void MacroAssembler::MovFromFloatParameter(const DoubleRegister dst) {
3833 if (IsMipsSoftFloatABI) {
3834 Move(dst, a0, a1);
3835 } else {
3836 Move(dst, f12); // Reg f12 is o32 ABI FP first argument value.
3837 }
3838}
3839
3840
3841void MacroAssembler::MovToFloatParameter(DoubleRegister src) {
3842 if (!IsMipsSoftFloatABI) {
3843 Move(f12, src);
3844 } else {
3845 Move(a0, a1, src);
3846 }
3847}
3848
3849
3850void MacroAssembler::MovToFloatResult(DoubleRegister src) {
3851 if (!IsMipsSoftFloatABI) {
3852 Move(f0, src);
3853 } else {
3854 Move(v0, v1, src);
3855 }
3856}
3857
3858
3859void MacroAssembler::MovToFloatParameters(DoubleRegister src1,
3860 DoubleRegister src2) {
3861 if (!IsMipsSoftFloatABI) {
3862 const DoubleRegister fparg2 = (kMipsAbi == kN64) ? f13 : f14;
3863 if (src2.is(f12)) {
3864 DCHECK(!src1.is(fparg2));
3865 Move(fparg2, src2);
3866 Move(f12, src1);
3867 } else {
3868 Move(f12, src1);
3869 Move(fparg2, src2);
3870 }
3871 } else {
3872 Move(a0, a1, src1);
3873 Move(a2, a3, src2);
3874 }
3875}
3876
3877
3878// -----------------------------------------------------------------------------
3879// JavaScript invokes.
3880
3881void MacroAssembler::InvokePrologue(const ParameterCount& expected,
3882 const ParameterCount& actual,
3883 Handle<Code> code_constant,
3884 Register code_reg,
3885 Label* done,
3886 bool* definitely_mismatches,
3887 InvokeFlag flag,
3888 const CallWrapper& call_wrapper) {
3889 bool definitely_matches = false;
3890 *definitely_mismatches = false;
3891 Label regular_invoke;
3892
3893 // Check whether the expected and actual arguments count match. If not,
3894 // setup registers according to contract with ArgumentsAdaptorTrampoline:
3895 // a0: actual arguments count
3896 // a1: function (passed through to callee)
3897 // a2: expected arguments count
3898
3899 // The code below is made a lot easier because the calling code already sets
3900 // up actual and expected registers according to the contract if values are
3901 // passed in registers.
3902 DCHECK(actual.is_immediate() || actual.reg().is(a0));
3903 DCHECK(expected.is_immediate() || expected.reg().is(a2));
3904 DCHECK((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(a3));
3905
3906 if (expected.is_immediate()) {
3907 DCHECK(actual.is_immediate());
3908 if (expected.immediate() == actual.immediate()) {
3909 definitely_matches = true;
3910 } else {
3911 li(a0, Operand(actual.immediate()));
3912 const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
3913 if (expected.immediate() == sentinel) {
3914 // Don't worry about adapting arguments for builtins that
3915 // don't want that done. Skip adaption code by making it look
3916 // like we have a match between expected and actual number of
3917 // arguments.
3918 definitely_matches = true;
3919 } else {
3920 *definitely_mismatches = true;
3921 li(a2, Operand(expected.immediate()));
3922 }
3923 }
3924 } else if (actual.is_immediate()) {
3925 Branch(&regular_invoke, eq, expected.reg(), Operand(actual.immediate()));
3926 li(a0, Operand(actual.immediate()));
3927 } else {
3928 Branch(&regular_invoke, eq, expected.reg(), Operand(actual.reg()));
3929 }
3930
3931 if (!definitely_matches) {
3932 if (!code_constant.is_null()) {
3933 li(a3, Operand(code_constant));
3934 daddiu(a3, a3, Code::kHeaderSize - kHeapObjectTag);
3935 }
3936
3937 Handle<Code> adaptor =
3938 isolate()->builtins()->ArgumentsAdaptorTrampoline();
3939 if (flag == CALL_FUNCTION) {
3940 call_wrapper.BeforeCall(CallSize(adaptor));
3941 Call(adaptor);
3942 call_wrapper.AfterCall();
3943 if (!*definitely_mismatches) {
3944 Branch(done);
3945 }
3946 } else {
3947 Jump(adaptor, RelocInfo::CODE_TARGET);
3948 }
3949 bind(&regular_invoke);
3950 }
3951}
3952
3953
3954void MacroAssembler::InvokeCode(Register code,
3955 const ParameterCount& expected,
3956 const ParameterCount& actual,
3957 InvokeFlag flag,
3958 const CallWrapper& call_wrapper) {
3959 // You can't call a function without a valid frame.
3960 DCHECK(flag == JUMP_FUNCTION || has_frame());
3961
3962 Label done;
3963
3964 bool definitely_mismatches = false;
3965 InvokePrologue(expected, actual, Handle<Code>::null(), code,
3966 &done, &definitely_mismatches, flag,
3967 call_wrapper);
3968 if (!definitely_mismatches) {
3969 if (flag == CALL_FUNCTION) {
3970 call_wrapper.BeforeCall(CallSize(code));
3971 Call(code);
3972 call_wrapper.AfterCall();
3973 } else {
3974 DCHECK(flag == JUMP_FUNCTION);
3975 Jump(code);
3976 }
3977 // Continue here if InvokePrologue does handle the invocation due to
3978 // mismatched parameter counts.
3979 bind(&done);
3980 }
3981}
3982
3983
3984void MacroAssembler::InvokeFunction(Register function,
3985 const ParameterCount& actual,
3986 InvokeFlag flag,
3987 const CallWrapper& call_wrapper) {
3988 // You can't call a function without a valid frame.
3989 DCHECK(flag == JUMP_FUNCTION || has_frame());
3990
3991 // Contract with called JS functions requires that function is passed in a1.
3992 DCHECK(function.is(a1));
3993 Register expected_reg = a2;
3994 Register code_reg = a3;
3995 ld(code_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
3996 ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
3997 // The argument count is stored as int32_t on 64-bit platforms.
3998 // TODO(plind): Smi on 32-bit platforms.
3999 lw(expected_reg,
4000 FieldMemOperand(code_reg,
4001 SharedFunctionInfo::kFormalParameterCountOffset));
4002 ld(code_reg, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
4003 ParameterCount expected(expected_reg);
4004 InvokeCode(code_reg, expected, actual, flag, call_wrapper);
4005}
4006
4007
4008void MacroAssembler::InvokeFunction(Register function,
4009 const ParameterCount& expected,
4010 const ParameterCount& actual,
4011 InvokeFlag flag,
4012 const CallWrapper& call_wrapper) {
4013 // You can't call a function without a valid frame.
4014 DCHECK(flag == JUMP_FUNCTION || has_frame());
4015
4016 // Contract with called JS functions requires that function is passed in a1.
4017 DCHECK(function.is(a1));
4018
4019 // Get the function and setup the context.
4020 ld(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
4021
4022 // We call indirectly through the code field in the function to
4023 // allow recompilation to take effect without changing any of the
4024 // call sites.
4025 ld(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
4026 InvokeCode(a3, expected, actual, flag, call_wrapper);
4027}
4028
4029
4030void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
4031 const ParameterCount& expected,
4032 const ParameterCount& actual,
4033 InvokeFlag flag,
4034 const CallWrapper& call_wrapper) {
4035 li(a1, function);
4036 InvokeFunction(a1, expected, actual, flag, call_wrapper);
4037}
4038
4039
4040void MacroAssembler::IsObjectJSObjectType(Register heap_object,
4041 Register map,
4042 Register scratch,
4043 Label* fail) {
4044 ld(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
4045 IsInstanceJSObjectType(map, scratch, fail);
4046}
4047
4048
4049void MacroAssembler::IsInstanceJSObjectType(Register map,
4050 Register scratch,
4051 Label* fail) {
4052 lbu(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
4053 Branch(fail, lt, scratch, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
4054 Branch(fail, gt, scratch, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
4055}
4056
4057
4058void MacroAssembler::IsObjectJSStringType(Register object,
4059 Register scratch,
4060 Label* fail) {
4061 DCHECK(kNotStringTag != 0);
4062
4063 ld(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
4064 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
4065 And(scratch, scratch, Operand(kIsNotStringMask));
4066 Branch(fail, ne, scratch, Operand(zero_reg));
4067}
4068
4069
4070void MacroAssembler::IsObjectNameType(Register object,
4071 Register scratch,
4072 Label* fail) {
4073 ld(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
4074 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
4075 Branch(fail, hi, scratch, Operand(LAST_NAME_TYPE));
4076}
4077
4078
4079// ---------------------------------------------------------------------------
4080// Support functions.
4081
4082
4083void MacroAssembler::TryGetFunctionPrototype(Register function,
4084 Register result,
4085 Register scratch,
4086 Label* miss,
4087 bool miss_on_bound_function) {
4088 Label non_instance;
4089 if (miss_on_bound_function) {
4090 // Check that the receiver isn't a smi.
4091 JumpIfSmi(function, miss);
4092
4093 // Check that the function really is a function. Load map into result reg.
4094 GetObjectType(function, result, scratch);
4095 Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
4096
4097 ld(scratch,
4098 FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
4099 lwu(scratch,
4100 FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
4101 And(scratch, scratch,
4102 Operand(1 << SharedFunctionInfo::kBoundFunction));
4103 Branch(miss, ne, scratch, Operand(zero_reg));
4104
4105 // Make sure that the function has an instance prototype.
4106 lbu(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
4107 And(scratch, scratch, Operand(1 << Map::kHasNonInstancePrototype));
4108 Branch(&non_instance, ne, scratch, Operand(zero_reg));
4109 }
4110
4111 // Get the prototype or initial map from the function.
4112 ld(result,
4113 FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
4114
4115 // If the prototype or initial map is the hole, don't return it and
4116 // simply miss the cache instead. This will allow us to allocate a
4117 // prototype object on-demand in the runtime system.
4118 LoadRoot(t8, Heap::kTheHoleValueRootIndex);
4119 Branch(miss, eq, result, Operand(t8));
4120
4121 // If the function does not have an initial map, we're done.
4122 Label done;
4123 GetObjectType(result, scratch, scratch);
4124 Branch(&done, ne, scratch, Operand(MAP_TYPE));
4125
4126 // Get the prototype from the initial map.
4127 ld(result, FieldMemOperand(result, Map::kPrototypeOffset));
4128
4129 if (miss_on_bound_function) {
4130 jmp(&done);
4131
4132 // Non-instance prototype: Fetch prototype from constructor field
4133 // in initial map.
4134 bind(&non_instance);
4135 ld(result, FieldMemOperand(result, Map::kConstructorOffset));
4136 }
4137
4138 // All done.
4139 bind(&done);
4140}
4141
4142
4143void MacroAssembler::GetObjectType(Register object,
4144 Register map,
4145 Register type_reg) {
4146 ld(map, FieldMemOperand(object, HeapObject::kMapOffset));
4147 lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
4148}
4149
4150
4151// -----------------------------------------------------------------------------
4152// Runtime calls.
4153
4154void MacroAssembler::CallStub(CodeStub* stub,
4155 TypeFeedbackId ast_id,
4156 Condition cond,
4157 Register r1,
4158 const Operand& r2,
4159 BranchDelaySlot bd) {
4160 DCHECK(AllowThisStubCall(stub)); // Stub calls are not allowed in some stubs.
4161 Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id,
4162 cond, r1, r2, bd);
4163}
4164
4165
4166void MacroAssembler::TailCallStub(CodeStub* stub,
4167 Condition cond,
4168 Register r1,
4169 const Operand& r2,
4170 BranchDelaySlot bd) {
4171 Jump(stub->GetCode(), RelocInfo::CODE_TARGET, cond, r1, r2, bd);
4172}
4173
4174
4175static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
4176 int64_t offset = (ref0.address() - ref1.address());
4177 DCHECK(static_cast<int>(offset) == offset);
4178 return static_cast<int>(offset);
4179}
4180
4181
4182void MacroAssembler::CallApiFunctionAndReturn(
4183 Register function_address,
4184 ExternalReference thunk_ref,
4185 int stack_space,
4186 MemOperand return_value_operand,
4187 MemOperand* context_restore_operand) {
4188 ExternalReference next_address =
4189 ExternalReference::handle_scope_next_address(isolate());
4190 const int kNextOffset = 0;
4191 const int kLimitOffset = AddressOffset(
4192 ExternalReference::handle_scope_limit_address(isolate()),
4193 next_address);
4194 const int kLevelOffset = AddressOffset(
4195 ExternalReference::handle_scope_level_address(isolate()),
4196 next_address);
4197
4198 DCHECK(function_address.is(a1) || function_address.is(a2));
4199
4200 Label profiler_disabled;
4201 Label end_profiler_check;
4202 li(t9, Operand(ExternalReference::is_profiling_address(isolate())));
4203 lb(t9, MemOperand(t9, 0));
4204 Branch(&profiler_disabled, eq, t9, Operand(zero_reg));
4205
4206 // Additional parameter is the address of the actual callback.
4207 li(t9, Operand(thunk_ref));
4208 jmp(&end_profiler_check);
4209
4210 bind(&profiler_disabled);
4211 mov(t9, function_address);
4212 bind(&end_profiler_check);
4213
4214 // Allocate HandleScope in callee-save registers.
4215 li(s3, Operand(next_address));
4216 ld(s0, MemOperand(s3, kNextOffset));
4217 ld(s1, MemOperand(s3, kLimitOffset));
4218 ld(s2, MemOperand(s3, kLevelOffset));
4219 Daddu(s2, s2, Operand(1));
4220 sd(s2, MemOperand(s3, kLevelOffset));
4221
4222 if (FLAG_log_timer_events) {
4223 FrameScope frame(this, StackFrame::MANUAL);
4224 PushSafepointRegisters();
4225 PrepareCallCFunction(1, a0);
4226 li(a0, Operand(ExternalReference::isolate_address(isolate())));
4227 CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
4228 PopSafepointRegisters();
4229 }
4230
4231 // Native call returns to the DirectCEntry stub which redirects to the
4232 // return address pushed on stack (could have moved after GC).
4233 // DirectCEntry stub itself is generated early and never moves.
4234 DirectCEntryStub stub(isolate());
4235 stub.GenerateCall(this, t9);
4236
4237 if (FLAG_log_timer_events) {
4238 FrameScope frame(this, StackFrame::MANUAL);
4239 PushSafepointRegisters();
4240 PrepareCallCFunction(1, a0);
4241 li(a0, Operand(ExternalReference::isolate_address(isolate())));
4242 CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
4243 PopSafepointRegisters();
4244 }
4245
4246 Label promote_scheduled_exception;
4247 Label exception_handled;
4248 Label delete_allocated_handles;
4249 Label leave_exit_frame;
4250 Label return_value_loaded;
4251
4252 // Load value from ReturnValue.
4253 ld(v0, return_value_operand);
4254 bind(&return_value_loaded);
4255
4256 // No more valid handles (the result handle was the last one). Restore
4257 // previous handle scope.
4258 sd(s0, MemOperand(s3, kNextOffset));
4259 if (emit_debug_code()) {
4260 ld(a1, MemOperand(s3, kLevelOffset));
4261 Check(eq, kUnexpectedLevelAfterReturnFromApiCall, a1, Operand(s2));
4262 }
4263 Dsubu(s2, s2, Operand(1));
4264 sd(s2, MemOperand(s3, kLevelOffset));
4265 ld(at, MemOperand(s3, kLimitOffset));
4266 Branch(&delete_allocated_handles, ne, s1, Operand(at));
4267
4268 // Check if the function scheduled an exception.
4269 bind(&leave_exit_frame);
4270 LoadRoot(a4, Heap::kTheHoleValueRootIndex);
4271 li(at, Operand(ExternalReference::scheduled_exception_address(isolate())));
4272 ld(a5, MemOperand(at));
4273 Branch(&promote_scheduled_exception, ne, a4, Operand(a5));
4274 bind(&exception_handled);
4275
4276 bool restore_context = context_restore_operand != NULL;
4277 if (restore_context) {
4278 ld(cp, *context_restore_operand);
4279 }
4280 li(s0, Operand(stack_space));
4281 LeaveExitFrame(false, s0, !restore_context, EMIT_RETURN);
4282
4283 bind(&promote_scheduled_exception);
4284 {
4285 FrameScope frame(this, StackFrame::INTERNAL);
4286 CallExternalReference(
4287 ExternalReference(Runtime::kPromoteScheduledException, isolate()),
4288 0);
4289 }
4290 jmp(&exception_handled);
4291
4292 // HandleScope limit has changed. Delete allocated extensions.
4293 bind(&delete_allocated_handles);
4294 sd(s1, MemOperand(s3, kLimitOffset));
4295 mov(s0, v0);
4296 mov(a0, v0);
4297 PrepareCallCFunction(1, s1);
4298 li(a0, Operand(ExternalReference::isolate_address(isolate())));
4299 CallCFunction(ExternalReference::delete_handle_scope_extensions(isolate()),
4300 1);
4301 mov(v0, s0);
4302 jmp(&leave_exit_frame);
4303}
4304
4305
4306bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
4307 return has_frame_ || !stub->SometimesSetsUpAFrame();
4308}
4309
4310
4311void MacroAssembler::IndexFromHash(Register hash, Register index) {
4312 // If the hash field contains an array index pick it out. The assert checks
4313 // that the constants for the maximum number of digits for an array index
4314 // cached in the hash field and the number of bits reserved for it does not
4315 // conflict.
4316 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
4317 (1 << String::kArrayIndexValueBits));
4318 DecodeFieldToSmi<String::ArrayIndexValueBits>(index, hash);
4319}
4320
4321
4322void MacroAssembler::ObjectToDoubleFPURegister(Register object,
4323 FPURegister result,
4324 Register scratch1,
4325 Register scratch2,
4326 Register heap_number_map,
4327 Label* not_number,
4328 ObjectToDoubleFlags flags) {
4329 Label done;
4330 if ((flags & OBJECT_NOT_SMI) == 0) {
4331 Label not_smi;
4332 JumpIfNotSmi(object, &not_smi);
4333 // Remove smi tag and convert to double.
4334 // dsra(scratch1, object, kSmiTagSize);
4335 dsra32(scratch1, object, 0);
4336 mtc1(scratch1, result);
4337 cvt_d_w(result, result);
4338 Branch(&done);
4339 bind(&not_smi);
4340 }
4341 // Check for heap number and load double value from it.
4342 ld(scratch1, FieldMemOperand(object, HeapObject::kMapOffset));
4343 Branch(not_number, ne, scratch1, Operand(heap_number_map));
4344
4345 if ((flags & AVOID_NANS_AND_INFINITIES) != 0) {
4346 // If exponent is all ones the number is either a NaN or +/-Infinity.
4347 Register exponent = scratch1;
4348 Register mask_reg = scratch2;
4349 lwu(exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
4350 li(mask_reg, HeapNumber::kExponentMask);
4351
4352 And(exponent, exponent, mask_reg);
4353 Branch(not_number, eq, exponent, Operand(mask_reg));
4354 }
4355 ldc1(result, FieldMemOperand(object, HeapNumber::kValueOffset));
4356 bind(&done);
4357}
4358
4359
4360void MacroAssembler::SmiToDoubleFPURegister(Register smi,
4361 FPURegister value,
4362 Register scratch1) {
4363 // dsra(scratch1, smi, kSmiTagSize);
4364 dsra32(scratch1, smi, 0);
4365 mtc1(scratch1, value);
4366 cvt_d_w(value, value);
4367}
4368
4369
4370void MacroAssembler::AdduAndCheckForOverflow(Register dst,
4371 Register left,
4372 Register right,
4373 Register overflow_dst,
4374 Register scratch) {
4375 DCHECK(!dst.is(overflow_dst));
4376 DCHECK(!dst.is(scratch));
4377 DCHECK(!overflow_dst.is(scratch));
4378 DCHECK(!overflow_dst.is(left));
4379 DCHECK(!overflow_dst.is(right));
4380
4381 if (left.is(right) && dst.is(left)) {
4382 DCHECK(!dst.is(t9));
4383 DCHECK(!scratch.is(t9));
4384 DCHECK(!left.is(t9));
4385 DCHECK(!right.is(t9));
4386 DCHECK(!overflow_dst.is(t9));
4387 mov(t9, right);
4388 right = t9;
4389 }
4390
4391 if (dst.is(left)) {
4392 mov(scratch, left); // Preserve left.
4393 daddu(dst, left, right); // Left is overwritten.
4394 xor_(scratch, dst, scratch); // Original left.
4395 xor_(overflow_dst, dst, right);
4396 and_(overflow_dst, overflow_dst, scratch);
4397 } else if (dst.is(right)) {
4398 mov(scratch, right); // Preserve right.
4399 daddu(dst, left, right); // Right is overwritten.
4400 xor_(scratch, dst, scratch); // Original right.
4401 xor_(overflow_dst, dst, left);
4402 and_(overflow_dst, overflow_dst, scratch);
4403 } else {
4404 daddu(dst, left, right);
4405 xor_(overflow_dst, dst, left);
4406 xor_(scratch, dst, right);
4407 and_(overflow_dst, scratch, overflow_dst);
4408 }
4409}
4410
4411
4412void MacroAssembler::SubuAndCheckForOverflow(Register dst,
4413 Register left,
4414 Register right,
4415 Register overflow_dst,
4416 Register scratch) {
4417 DCHECK(!dst.is(overflow_dst));
4418 DCHECK(!dst.is(scratch));
4419 DCHECK(!overflow_dst.is(scratch));
4420 DCHECK(!overflow_dst.is(left));
4421 DCHECK(!overflow_dst.is(right));
4422 DCHECK(!scratch.is(left));
4423 DCHECK(!scratch.is(right));
4424
4425 // This happens with some crankshaft code. Since Subu works fine if
4426 // left == right, let's not make that restriction here.
4427 if (left.is(right)) {
4428 mov(dst, zero_reg);
4429 mov(overflow_dst, zero_reg);
4430 return;
4431 }
4432
4433 if (dst.is(left)) {
4434 mov(scratch, left); // Preserve left.
4435 dsubu(dst, left, right); // Left is overwritten.
4436 xor_(overflow_dst, dst, scratch); // scratch is original left.
4437 xor_(scratch, scratch, right); // scratch is original left.
4438 and_(overflow_dst, scratch, overflow_dst);
4439 } else if (dst.is(right)) {
4440 mov(scratch, right); // Preserve right.
4441 dsubu(dst, left, right); // Right is overwritten.
4442 xor_(overflow_dst, dst, left);
4443 xor_(scratch, left, scratch); // Original right.
4444 and_(overflow_dst, scratch, overflow_dst);
4445 } else {
4446 dsubu(dst, left, right);
4447 xor_(overflow_dst, dst, left);
4448 xor_(scratch, left, right);
4449 and_(overflow_dst, scratch, overflow_dst);
4450 }
4451}
4452
4453
4454void MacroAssembler::CallRuntime(const Runtime::Function* f,
4455 int num_arguments,
4456 SaveFPRegsMode save_doubles) {
4457 // All parameters are on the stack. v0 has the return value after call.
4458
4459 // If the expected number of arguments of the runtime function is
4460 // constant, we check that the actual number of arguments match the
4461 // expectation.
4462 CHECK(f->nargs < 0 || f->nargs == num_arguments);
4463
4464 // TODO(1236192): Most runtime routines don't need the number of
4465 // arguments passed in because it is constant. At some point we
4466 // should remove this need and make the runtime routine entry code
4467 // smarter.
4468 PrepareCEntryArgs(num_arguments);
4469 PrepareCEntryFunction(ExternalReference(f, isolate()));
4470 CEntryStub stub(isolate(), 1, save_doubles);
4471 CallStub(&stub);
4472}
4473
4474
4475void MacroAssembler::CallExternalReference(const ExternalReference& ext,
4476 int num_arguments,
4477 BranchDelaySlot bd) {
4478 PrepareCEntryArgs(num_arguments);
4479 PrepareCEntryFunction(ext);
4480
4481 CEntryStub stub(isolate(), 1);
4482 CallStub(&stub, TypeFeedbackId::None(), al, zero_reg, Operand(zero_reg), bd);
4483}
4484
4485
4486void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
4487 int num_arguments,
4488 int result_size) {
4489 // TODO(1236192): Most runtime routines don't need the number of
4490 // arguments passed in because it is constant. At some point we
4491 // should remove this need and make the runtime routine entry code
4492 // smarter.
4493 PrepareCEntryArgs(num_arguments);
4494 JumpToExternalReference(ext);
4495}
4496
4497
4498void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
4499 int num_arguments,
4500 int result_size) {
4501 TailCallExternalReference(ExternalReference(fid, isolate()),
4502 num_arguments,
4503 result_size);
4504}
4505
4506
4507void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin,
4508 BranchDelaySlot bd) {
4509 PrepareCEntryFunction(builtin);
4510 CEntryStub stub(isolate(), 1);
4511 Jump(stub.GetCode(),
4512 RelocInfo::CODE_TARGET,
4513 al,
4514 zero_reg,
4515 Operand(zero_reg),
4516 bd);
4517}
4518
4519
4520void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
4521 InvokeFlag flag,
4522 const CallWrapper& call_wrapper) {
4523 // You can't call a builtin without a valid frame.
4524 DCHECK(flag == JUMP_FUNCTION || has_frame());
4525
4526 GetBuiltinEntry(t9, id);
4527 if (flag == CALL_FUNCTION) {
4528 call_wrapper.BeforeCall(CallSize(t9));
4529 Call(t9);
4530 call_wrapper.AfterCall();
4531 } else {
4532 DCHECK(flag == JUMP_FUNCTION);
4533 Jump(t9);
4534 }
4535}
4536
4537
4538void MacroAssembler::GetBuiltinFunction(Register target,
4539 Builtins::JavaScript id) {
4540 // Load the builtins object into target register.
4541 ld(target, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
4542 ld(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
4543 // Load the JavaScript builtin function from the builtins object.
4544 ld(target, FieldMemOperand(target,
4545 JSBuiltinsObject::OffsetOfFunctionWithId(id)));
4546}
4547
4548
4549void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
4550 DCHECK(!target.is(a1));
4551 GetBuiltinFunction(a1, id);
4552 // Load the code entry point from the builtins object.
4553 ld(target, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
4554}
4555
4556
4557void MacroAssembler::SetCounter(StatsCounter* counter, int value,
4558 Register scratch1, Register scratch2) {
4559 if (FLAG_native_code_counters && counter->Enabled()) {
4560 li(scratch1, Operand(value));
4561 li(scratch2, Operand(ExternalReference(counter)));
4562 sd(scratch1, MemOperand(scratch2));
4563 }
4564}
4565
4566
4567void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
4568 Register scratch1, Register scratch2) {
4569 DCHECK(value > 0);
4570 if (FLAG_native_code_counters && counter->Enabled()) {
4571 li(scratch2, Operand(ExternalReference(counter)));
4572 ld(scratch1, MemOperand(scratch2));
4573 Daddu(scratch1, scratch1, Operand(value));
4574 sd(scratch1, MemOperand(scratch2));
4575 }
4576}
4577
4578
4579void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
4580 Register scratch1, Register scratch2) {
4581 DCHECK(value > 0);
4582 if (FLAG_native_code_counters && counter->Enabled()) {
4583 li(scratch2, Operand(ExternalReference(counter)));
4584 ld(scratch1, MemOperand(scratch2));
4585 Dsubu(scratch1, scratch1, Operand(value));
4586 sd(scratch1, MemOperand(scratch2));
4587 }
4588}
4589
4590
4591// -----------------------------------------------------------------------------
4592// Debugging.
4593
4594void MacroAssembler::Assert(Condition cc, BailoutReason reason,
4595 Register rs, Operand rt) {
4596 if (emit_debug_code())
4597 Check(cc, reason, rs, rt);
4598}
4599
4600
4601void MacroAssembler::AssertFastElements(Register elements) {
4602 if (emit_debug_code()) {
4603 DCHECK(!elements.is(at));
4604 Label ok;
4605 push(elements);
4606 ld(elements, FieldMemOperand(elements, HeapObject::kMapOffset));
4607 LoadRoot(at, Heap::kFixedArrayMapRootIndex);
4608 Branch(&ok, eq, elements, Operand(at));
4609 LoadRoot(at, Heap::kFixedDoubleArrayMapRootIndex);
4610 Branch(&ok, eq, elements, Operand(at));
4611 LoadRoot(at, Heap::kFixedCOWArrayMapRootIndex);
4612 Branch(&ok, eq, elements, Operand(at));
4613 Abort(kJSObjectWithFastElementsMapHasSlowElements);
4614 bind(&ok);
4615 pop(elements);
4616 }
4617}
4618
4619
4620void MacroAssembler::Check(Condition cc, BailoutReason reason,
4621 Register rs, Operand rt) {
4622 Label L;
4623 Branch(&L, cc, rs, rt);
4624 Abort(reason);
4625 // Will not return here.
4626 bind(&L);
4627}
4628
4629
4630void MacroAssembler::Abort(BailoutReason reason) {
4631 Label abort_start;
4632 bind(&abort_start);
4633#ifdef DEBUG
4634 const char* msg = GetBailoutReason(reason);
4635 if (msg != NULL) {
4636 RecordComment("Abort message: ");
4637 RecordComment(msg);
4638 }
4639
4640 if (FLAG_trap_on_abort) {
4641 stop(msg);
4642 return;
4643 }
4644#endif
4645
4646 li(a0, Operand(Smi::FromInt(reason)));
4647 push(a0);
4648 // Disable stub call restrictions to always allow calls to abort.
4649 if (!has_frame_) {
4650 // We don't actually want to generate a pile of code for this, so just
4651 // claim there is a stack frame, without generating one.
4652 FrameScope scope(this, StackFrame::NONE);
4653 CallRuntime(Runtime::kAbort, 1);
4654 } else {
4655 CallRuntime(Runtime::kAbort, 1);
4656 }
4657 // Will not return here.
4658 if (is_trampoline_pool_blocked()) {
4659 // If the calling code cares about the exact number of
4660 // instructions generated, we insert padding here to keep the size
4661 // of the Abort macro constant.
4662 // Currently in debug mode with debug_code enabled the number of
4663 // generated instructions is 10, so we use this as a maximum value.
4664 static const int kExpectedAbortInstructions = 10;
4665 int abort_instructions = InstructionsGeneratedSince(&abort_start);
4666 DCHECK(abort_instructions <= kExpectedAbortInstructions);
4667 while (abort_instructions++ < kExpectedAbortInstructions) {
4668 nop();
4669 }
4670 }
4671}
4672
4673
4674void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
4675 if (context_chain_length > 0) {
4676 // Move up the chain of contexts to the context containing the slot.
4677 ld(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
4678 for (int i = 1; i < context_chain_length; i++) {
4679 ld(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
4680 }
4681 } else {
4682 // Slot is in the current function context. Move it into the
4683 // destination register in case we store into it (the write barrier
4684 // cannot be allowed to destroy the context in esi).
4685 Move(dst, cp);
4686 }
4687}
4688
4689
4690void MacroAssembler::LoadTransitionedArrayMapConditional(
4691 ElementsKind expected_kind,
4692 ElementsKind transitioned_kind,
4693 Register map_in_out,
4694 Register scratch,
4695 Label* no_map_match) {
4696 // Load the global or builtins object from the current context.
4697 ld(scratch,
4698 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
4699 ld(scratch, FieldMemOperand(scratch, GlobalObject::kNativeContextOffset));
4700
4701 // Check that the function's map is the same as the expected cached map.
4702 ld(scratch,
4703 MemOperand(scratch,
4704 Context::SlotOffset(Context::JS_ARRAY_MAPS_INDEX)));
4705 size_t offset = expected_kind * kPointerSize +
4706 FixedArrayBase::kHeaderSize;
4707 ld(at, FieldMemOperand(scratch, offset));
4708 Branch(no_map_match, ne, map_in_out, Operand(at));
4709
4710 // Use the transitioned cached map.
4711 offset = transitioned_kind * kPointerSize +
4712 FixedArrayBase::kHeaderSize;
4713 ld(map_in_out, FieldMemOperand(scratch, offset));
4714}
4715
4716
4717void MacroAssembler::LoadGlobalFunction(int index, Register function) {
4718 // Load the global or builtins object from the current context.
4719 ld(function,
4720 MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
4721 // Load the native context from the global or builtins object.
4722 ld(function, FieldMemOperand(function,
4723 GlobalObject::kNativeContextOffset));
4724 // Load the function from the native context.
4725 ld(function, MemOperand(function, Context::SlotOffset(index)));
4726}
4727
4728
4729void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
4730 Register map,
4731 Register scratch) {
4732 // Load the initial map. The global functions all have initial maps.
4733 ld(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
4734 if (emit_debug_code()) {
4735 Label ok, fail;
4736 CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
4737 Branch(&ok);
4738 bind(&fail);
4739 Abort(kGlobalFunctionsMustHaveInitialMap);
4740 bind(&ok);
4741 }
4742}
4743
4744
4745void MacroAssembler::StubPrologue() {
4746 Push(ra, fp, cp);
4747 Push(Smi::FromInt(StackFrame::STUB));
4748 // Adjust FP to point to saved FP.
4749 Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
4750}
4751
4752
4753void MacroAssembler::Prologue(bool code_pre_aging) {
4754 PredictableCodeSizeScope predictible_code_size_scope(
4755 this, kNoCodeAgeSequenceLength);
4756 // The following three instructions must remain together and unmodified
4757 // for code aging to work properly.
4758 if (code_pre_aging) {
4759 // Pre-age the code.
4760 Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
4761 nop(Assembler::CODE_AGE_MARKER_NOP);
4762 // Load the stub address to t9 and call it,
4763 // GetCodeAgeAndParity() extracts the stub address from this instruction.
4764 li(t9,
4765 Operand(reinterpret_cast<uint64_t>(stub->instruction_start())),
4766 ADDRESS_LOAD);
4767 nop(); // Prevent jalr to jal optimization.
4768 jalr(t9, a0);
4769 nop(); // Branch delay slot nop.
4770 nop(); // Pad the empty space.
4771 } else {
4772 Push(ra, fp, cp, a1);
4773 nop(Assembler::CODE_AGE_SEQUENCE_NOP);
4774 nop(Assembler::CODE_AGE_SEQUENCE_NOP);
4775 nop(Assembler::CODE_AGE_SEQUENCE_NOP);
4776 // Adjust fp to point to caller's fp.
4777 Daddu(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
4778 }
4779}
4780
4781
4782void MacroAssembler::EnterFrame(StackFrame::Type type) {
4783 daddiu(sp, sp, -5 * kPointerSize);
4784 li(t8, Operand(Smi::FromInt(type)));
4785 li(t9, Operand(CodeObject()), CONSTANT_SIZE);
4786 sd(ra, MemOperand(sp, 4 * kPointerSize));
4787 sd(fp, MemOperand(sp, 3 * kPointerSize));
4788 sd(cp, MemOperand(sp, 2 * kPointerSize));
4789 sd(t8, MemOperand(sp, 1 * kPointerSize));
4790 sd(t9, MemOperand(sp, 0 * kPointerSize));
4791 // Adjust FP to point to saved FP.
4792 Daddu(fp, sp,
4793 Operand(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize));
4794}
4795
4796
4797void MacroAssembler::LeaveFrame(StackFrame::Type type) {
4798 mov(sp, fp);
4799 ld(fp, MemOperand(sp, 0 * kPointerSize));
4800 ld(ra, MemOperand(sp, 1 * kPointerSize));
4801 daddiu(sp, sp, 2 * kPointerSize);
4802}
4803
4804
4805void MacroAssembler::EnterExitFrame(bool save_doubles,
4806 int stack_space) {
4807 // Set up the frame structure on the stack.
4808 STATIC_ASSERT(2 * kPointerSize == ExitFrameConstants::kCallerSPDisplacement);
4809 STATIC_ASSERT(1 * kPointerSize == ExitFrameConstants::kCallerPCOffset);
4810 STATIC_ASSERT(0 * kPointerSize == ExitFrameConstants::kCallerFPOffset);
4811
4812 // This is how the stack will look:
4813 // fp + 2 (==kCallerSPDisplacement) - old stack's end
4814 // [fp + 1 (==kCallerPCOffset)] - saved old ra
4815 // [fp + 0 (==kCallerFPOffset)] - saved old fp
4816 // [fp - 1 (==kSPOffset)] - sp of the called function
4817 // [fp - 2 (==kCodeOffset)] - CodeObject
4818 // fp - (2 + stack_space + alignment) == sp == [fp - kSPOffset] - top of the
4819 // new stack (will contain saved ra)
4820
4821 // Save registers.
4822 daddiu(sp, sp, -4 * kPointerSize);
4823 sd(ra, MemOperand(sp, 3 * kPointerSize));
4824 sd(fp, MemOperand(sp, 2 * kPointerSize));
4825 daddiu(fp, sp, 2 * kPointerSize); // Set up new frame pointer.
4826
4827 if (emit_debug_code()) {
4828 sd(zero_reg, MemOperand(fp, ExitFrameConstants::kSPOffset));
4829 }
4830
4831 // Accessed from ExitFrame::code_slot.
4832 li(t8, Operand(CodeObject()), CONSTANT_SIZE);
4833 sd(t8, MemOperand(fp, ExitFrameConstants::kCodeOffset));
4834
4835 // Save the frame pointer and the context in top.
4836 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
4837 sd(fp, MemOperand(t8));
4838 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
4839 sd(cp, MemOperand(t8));
4840
4841 const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
4842 if (save_doubles) {
4843 // The stack is already aligned to 0 modulo 8 for stores with sdc1.
4844 int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
4845 int space = kNumOfSavedRegisters * kDoubleSize ;
4846 Dsubu(sp, sp, Operand(space));
4847 // Remember: we only need to save every 2nd double FPU value.
4848 for (int i = 0; i < kNumOfSavedRegisters; i++) {
4849 FPURegister reg = FPURegister::from_code(2 * i);
4850 sdc1(reg, MemOperand(sp, i * kDoubleSize));
4851 }
4852 }
4853
4854 // Reserve place for the return address, stack space and an optional slot
4855 // (used by the DirectCEntryStub to hold the return value if a struct is
4856 // returned) and align the frame preparing for calling the runtime function.
4857 DCHECK(stack_space >= 0);
4858 Dsubu(sp, sp, Operand((stack_space + 2) * kPointerSize));
4859 if (frame_alignment > 0) {
4860 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
4861 And(sp, sp, Operand(-frame_alignment)); // Align stack.
4862 }
4863
4864 // Set the exit frame sp value to point just before the return address
4865 // location.
4866 daddiu(at, sp, kPointerSize);
4867 sd(at, MemOperand(fp, ExitFrameConstants::kSPOffset));
4868}
4869
4870
4871void MacroAssembler::LeaveExitFrame(bool save_doubles,
4872 Register argument_count,
4873 bool restore_context,
4874 bool do_return) {
4875 // Optionally restore all double registers.
4876 if (save_doubles) {
4877 // Remember: we only need to restore every 2nd double FPU value.
4878 int kNumOfSavedRegisters = FPURegister::kMaxNumRegisters / 2;
4879 Dsubu(t8, fp, Operand(ExitFrameConstants::kFrameSize +
4880 kNumOfSavedRegisters * kDoubleSize));
4881 for (int i = 0; i < kNumOfSavedRegisters; i++) {
4882 FPURegister reg = FPURegister::from_code(2 * i);
4883 ldc1(reg, MemOperand(t8, i * kDoubleSize));
4884 }
4885 }
4886
4887 // Clear top frame.
4888 li(t8, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate())));
4889 sd(zero_reg, MemOperand(t8));
4890
4891 // Restore current context from top and clear it in debug mode.
4892 if (restore_context) {
4893 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
4894 ld(cp, MemOperand(t8));
4895 }
4896#ifdef DEBUG
4897 li(t8, Operand(ExternalReference(Isolate::kContextAddress, isolate())));
4898 sd(a3, MemOperand(t8));
4899#endif
4900
4901 // Pop the arguments, restore registers, and return.
4902 mov(sp, fp); // Respect ABI stack constraint.
4903 ld(fp, MemOperand(sp, ExitFrameConstants::kCallerFPOffset));
4904 ld(ra, MemOperand(sp, ExitFrameConstants::kCallerPCOffset));
4905
4906 if (argument_count.is_valid()) {
4907 dsll(t8, argument_count, kPointerSizeLog2);
4908 daddu(sp, sp, t8);
4909 }
4910
4911 if (do_return) {
4912 Ret(USE_DELAY_SLOT);
4913 // If returning, the instruction in the delay slot will be the addiu below.
4914 }
4915 daddiu(sp, sp, 2 * kPointerSize);
4916}
4917
4918
4919void MacroAssembler::InitializeNewString(Register string,
4920 Register length,
4921 Heap::RootListIndex map_index,
4922 Register scratch1,
4923 Register scratch2) {
4924 // dsll(scratch1, length, kSmiTagSize);
4925 dsll32(scratch1, length, 0);
4926 LoadRoot(scratch2, map_index);
4927 sd(scratch1, FieldMemOperand(string, String::kLengthOffset));
4928 li(scratch1, Operand(String::kEmptyHashField));
4929 sd(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
4930 sd(scratch1, FieldMemOperand(string, String::kHashFieldOffset));
4931}
4932
4933
4934int MacroAssembler::ActivationFrameAlignment() {
4935#if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64
4936 // Running on the real platform. Use the alignment as mandated by the local
4937 // environment.
4938 // Note: This will break if we ever start generating snapshots on one Mips
4939 // platform for another Mips platform with a different alignment.
4940 return base::OS::ActivationFrameAlignment();
4941#else // V8_HOST_ARCH_MIPS
4942 // If we are using the simulator then we should always align to the expected
4943 // alignment. As the simulator is used to generate snapshots we do not know
4944 // if the target platform will need alignment, so this is controlled from a
4945 // flag.
4946 return FLAG_sim_stack_alignment;
4947#endif // V8_HOST_ARCH_MIPS
4948}
4949
4950
4951void MacroAssembler::AssertStackIsAligned() {
4952 if (emit_debug_code()) {
4953 const int frame_alignment = ActivationFrameAlignment();
4954 const int frame_alignment_mask = frame_alignment - 1;
4955
4956 if (frame_alignment > kPointerSize) {
4957 Label alignment_as_expected;
4958 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
4959 andi(at, sp, frame_alignment_mask);
4960 Branch(&alignment_as_expected, eq, at, Operand(zero_reg));
4961 // Don't use Check here, as it will call Runtime_Abort re-entering here.
4962 stop("Unexpected stack alignment");
4963 bind(&alignment_as_expected);
4964 }
4965 }
4966}
4967
4968
4969void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
4970 Register reg,
4971 Register scratch,
4972 Label* not_power_of_two_or_zero) {
4973 Dsubu(scratch, reg, Operand(1));
4974 Branch(USE_DELAY_SLOT, not_power_of_two_or_zero, lt,
4975 scratch, Operand(zero_reg));
4976 and_(at, scratch, reg); // In the delay slot.
4977 Branch(not_power_of_two_or_zero, ne, at, Operand(zero_reg));
4978}
4979
4980
4981void MacroAssembler::SmiTagCheckOverflow(Register reg, Register overflow) {
4982 DCHECK(!reg.is(overflow));
4983 mov(overflow, reg); // Save original value.
4984 SmiTag(reg);
4985 xor_(overflow, overflow, reg); // Overflow if (value ^ 2 * value) < 0.
4986}
4987
4988
4989void MacroAssembler::SmiTagCheckOverflow(Register dst,
4990 Register src,
4991 Register overflow) {
4992 if (dst.is(src)) {
4993 // Fall back to slower case.
4994 SmiTagCheckOverflow(dst, overflow);
4995 } else {
4996 DCHECK(!dst.is(src));
4997 DCHECK(!dst.is(overflow));
4998 DCHECK(!src.is(overflow));
4999 SmiTag(dst, src);
5000 xor_(overflow, dst, src); // Overflow if (value ^ 2 * value) < 0.
5001 }
5002}
5003
5004
5005void MacroAssembler::SmiLoadUntag(Register dst, MemOperand src) {
5006 if (SmiValuesAre32Bits()) {
5007 lw(dst, UntagSmiMemOperand(src.rm(), src.offset()));
5008 } else {
5009 lw(dst, src);
5010 SmiUntag(dst);
5011 }
5012}
5013
5014
5015void MacroAssembler::SmiLoadScale(Register dst, MemOperand src, int scale) {
5016 if (SmiValuesAre32Bits()) {
5017 // TODO(plind): not clear if lw or ld faster here, need micro-benchmark.
5018 lw(dst, UntagSmiMemOperand(src.rm(), src.offset()));
5019 dsll(dst, dst, scale);
5020 } else {
5021 lw(dst, src);
5022 DCHECK(scale >= kSmiTagSize);
5023 sll(dst, dst, scale - kSmiTagSize);
5024 }
5025}
5026
5027
5028// Returns 2 values: the Smi and a scaled version of the int within the Smi.
5029void MacroAssembler::SmiLoadWithScale(Register d_smi,
5030 Register d_scaled,
5031 MemOperand src,
5032 int scale) {
5033 if (SmiValuesAre32Bits()) {
5034 ld(d_smi, src);
5035 dsra(d_scaled, d_smi, kSmiShift - scale);
5036 } else {
5037 lw(d_smi, src);
5038 DCHECK(scale >= kSmiTagSize);
5039 sll(d_scaled, d_smi, scale - kSmiTagSize);
5040 }
5041}
5042
5043
5044// Returns 2 values: the untagged Smi (int32) and scaled version of that int.
5045void MacroAssembler::SmiLoadUntagWithScale(Register d_int,
5046 Register d_scaled,
5047 MemOperand src,
5048 int scale) {
5049 if (SmiValuesAre32Bits()) {
5050 lw(d_int, UntagSmiMemOperand(src.rm(), src.offset()));
5051 dsll(d_scaled, d_int, scale);
5052 } else {
5053 lw(d_int, src);
5054 // Need both the int and the scaled in, so use two instructions.
5055 SmiUntag(d_int);
5056 sll(d_scaled, d_int, scale);
5057 }
5058}
5059
5060
5061void MacroAssembler::UntagAndJumpIfSmi(Register dst,
5062 Register src,
5063 Label* smi_case) {
5064 // DCHECK(!dst.is(src));
5065 JumpIfSmi(src, smi_case, at, USE_DELAY_SLOT);
5066 SmiUntag(dst, src);
5067}
5068
5069
5070void MacroAssembler::UntagAndJumpIfNotSmi(Register dst,
5071 Register src,
5072 Label* non_smi_case) {
5073 // DCHECK(!dst.is(src));
5074 JumpIfNotSmi(src, non_smi_case, at, USE_DELAY_SLOT);
5075 SmiUntag(dst, src);
5076}
5077
5078void MacroAssembler::JumpIfSmi(Register value,
5079 Label* smi_label,
5080 Register scratch,
5081 BranchDelaySlot bd) {
5082 DCHECK_EQ(0, kSmiTag);
5083 andi(scratch, value, kSmiTagMask);
5084 Branch(bd, smi_label, eq, scratch, Operand(zero_reg));
5085}
5086
5087void MacroAssembler::JumpIfNotSmi(Register value,
5088 Label* not_smi_label,
5089 Register scratch,
5090 BranchDelaySlot bd) {
5091 DCHECK_EQ(0, kSmiTag);
5092 andi(scratch, value, kSmiTagMask);
5093 Branch(bd, not_smi_label, ne, scratch, Operand(zero_reg));
5094}
5095
5096
5097void MacroAssembler::JumpIfNotBothSmi(Register reg1,
5098 Register reg2,
5099 Label* on_not_both_smi) {
5100 STATIC_ASSERT(kSmiTag == 0);
5101 // TODO(plind): Find some better to fix this assert issue.
5102#if defined(__APPLE__)
5103 DCHECK_EQ(1, kSmiTagMask);
5104#else
5105 DCHECK_EQ((uint64_t)1, kSmiTagMask);
5106#endif
5107 or_(at, reg1, reg2);
5108 JumpIfNotSmi(at, on_not_both_smi);
5109}
5110
5111
5112void MacroAssembler::JumpIfEitherSmi(Register reg1,
5113 Register reg2,
5114 Label* on_either_smi) {
5115 STATIC_ASSERT(kSmiTag == 0);
5116 // TODO(plind): Find some better to fix this assert issue.
5117#if defined(__APPLE__)
5118 DCHECK_EQ(1, kSmiTagMask);
5119#else
5120 DCHECK_EQ((uint64_t)1, kSmiTagMask);
5121#endif
5122 // Both Smi tags must be 1 (not Smi).
5123 and_(at, reg1, reg2);
5124 JumpIfSmi(at, on_either_smi);
5125}
5126
5127
5128void MacroAssembler::AssertNotSmi(Register object) {
5129 if (emit_debug_code()) {
5130 STATIC_ASSERT(kSmiTag == 0);
5131 andi(at, object, kSmiTagMask);
5132 Check(ne, kOperandIsASmi, at, Operand(zero_reg));
5133 }
5134}
5135
5136
5137void MacroAssembler::AssertSmi(Register object) {
5138 if (emit_debug_code()) {
5139 STATIC_ASSERT(kSmiTag == 0);
5140 andi(at, object, kSmiTagMask);
5141 Check(eq, kOperandIsASmi, at, Operand(zero_reg));
5142 }
5143}
5144
5145
5146void MacroAssembler::AssertString(Register object) {
5147 if (emit_debug_code()) {
5148 STATIC_ASSERT(kSmiTag == 0);
5149 SmiTst(object, a4);
5150 Check(ne, kOperandIsASmiAndNotAString, a4, Operand(zero_reg));
5151 push(object);
5152 ld(object, FieldMemOperand(object, HeapObject::kMapOffset));
5153 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset));
5154 Check(lo, kOperandIsNotAString, object, Operand(FIRST_NONSTRING_TYPE));
5155 pop(object);
5156 }
5157}
5158
5159
5160void MacroAssembler::AssertName(Register object) {
5161 if (emit_debug_code()) {
5162 STATIC_ASSERT(kSmiTag == 0);
5163 SmiTst(object, a4);
5164 Check(ne, kOperandIsASmiAndNotAName, a4, Operand(zero_reg));
5165 push(object);
5166 ld(object, FieldMemOperand(object, HeapObject::kMapOffset));
5167 lbu(object, FieldMemOperand(object, Map::kInstanceTypeOffset));
5168 Check(le, kOperandIsNotAName, object, Operand(LAST_NAME_TYPE));
5169 pop(object);
5170 }
5171}
5172
5173
5174void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
5175 Register scratch) {
5176 if (emit_debug_code()) {
5177 Label done_checking;
5178 AssertNotSmi(object);
5179 LoadRoot(scratch, Heap::kUndefinedValueRootIndex);
5180 Branch(&done_checking, eq, object, Operand(scratch));
5181 push(object);
5182 ld(object, FieldMemOperand(object, HeapObject::kMapOffset));
5183 LoadRoot(scratch, Heap::kAllocationSiteMapRootIndex);
5184 Assert(eq, kExpectedUndefinedOrCell, object, Operand(scratch));
5185 pop(object);
5186 bind(&done_checking);
5187 }
5188}
5189
5190
5191void MacroAssembler::AssertIsRoot(Register reg, Heap::RootListIndex index) {
5192 if (emit_debug_code()) {
5193 DCHECK(!reg.is(at));
5194 LoadRoot(at, index);
5195 Check(eq, kHeapNumberMapRegisterClobbered, reg, Operand(at));
5196 }
5197}
5198
5199
5200void MacroAssembler::JumpIfNotHeapNumber(Register object,
5201 Register heap_number_map,
5202 Register scratch,
5203 Label* on_not_heap_number) {
5204 ld(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
5205 AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
5206 Branch(on_not_heap_number, ne, scratch, Operand(heap_number_map));
5207}
5208
5209
5210void MacroAssembler::LookupNumberStringCache(Register object,
5211 Register result,
5212 Register scratch1,
5213 Register scratch2,
5214 Register scratch3,
5215 Label* not_found) {
5216 // Use of registers. Register result is used as a temporary.
5217 Register number_string_cache = result;
5218 Register mask = scratch3;
5219
5220 // Load the number string cache.
5221 LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
5222
5223 // Make the hash mask from the length of the number string cache. It
5224 // contains two elements (number and string) for each cache entry.
5225 ld(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset));
5226 // Divide length by two (length is a smi).
5227 // dsra(mask, mask, kSmiTagSize + 1);
5228 dsra32(mask, mask, 1);
5229 Daddu(mask, mask, -1); // Make mask.
5230
5231 // Calculate the entry in the number string cache. The hash value in the
5232 // number string cache for smis is just the smi value, and the hash for
5233 // doubles is the xor of the upper and lower words. See
5234 // Heap::GetNumberStringCache.
5235 Label is_smi;
5236 Label load_result_from_cache;
5237 JumpIfSmi(object, &is_smi);
5238 CheckMap(object,
5239 scratch1,
5240 Heap::kHeapNumberMapRootIndex,
5241 not_found,
5242 DONT_DO_SMI_CHECK);
5243
5244 STATIC_ASSERT(8 == kDoubleSize);
5245 Daddu(scratch1,
5246 object,
5247 Operand(HeapNumber::kValueOffset - kHeapObjectTag));
5248 ld(scratch2, MemOperand(scratch1, kPointerSize));
5249 ld(scratch1, MemOperand(scratch1, 0));
5250 Xor(scratch1, scratch1, Operand(scratch2));
5251 And(scratch1, scratch1, Operand(mask));
5252
5253 // Calculate address of entry in string cache: each entry consists
5254 // of two pointer sized fields.
5255 dsll(scratch1, scratch1, kPointerSizeLog2 + 1);
5256 Daddu(scratch1, number_string_cache, scratch1);
5257
5258 Register probe = mask;
5259 ld(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
5260 JumpIfSmi(probe, not_found);
5261 ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset));
5262 ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset));
5263 BranchF(&load_result_from_cache, NULL, eq, f12, f14);
5264 Branch(not_found);
5265
5266 bind(&is_smi);
5267 Register scratch = scratch1;
5268 // dsra(scratch, object, 1); // Shift away the tag.
5269 dsra32(scratch, scratch, 0);
5270 And(scratch, mask, Operand(scratch));
5271
5272 // Calculate address of entry in string cache: each entry consists
5273 // of two pointer sized fields.
5274 dsll(scratch, scratch, kPointerSizeLog2 + 1);
5275 Daddu(scratch, number_string_cache, scratch);
5276
5277 // Check if the entry is the smi we are looking for.
5278 ld(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
5279 Branch(not_found, ne, object, Operand(probe));
5280
5281 // Get the result from the cache.
5282 bind(&load_result_from_cache);
5283 ld(result, FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
5284
5285 IncrementCounter(isolate()->counters()->number_to_string_native(),
5286 1,
5287 scratch1,
5288 scratch2);
5289}
5290
5291
5292void MacroAssembler::JumpIfNonSmisNotBothSequentialOneByteStrings(
5293 Register first, Register second, Register scratch1, Register scratch2,
5294 Label* failure) {
5295 // Test that both first and second are sequential one-byte strings.
5296 // Assume that they are non-smis.
5297 ld(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
5298 ld(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
5299 lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
5300 lbu(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
5301
5302 JumpIfBothInstanceTypesAreNotSequentialOneByte(scratch1, scratch2, scratch1,
5303 scratch2, failure);
5304}
5305
5306
5307void MacroAssembler::JumpIfNotBothSequentialOneByteStrings(Register first,
5308 Register second,
5309 Register scratch1,
5310 Register scratch2,
5311 Label* failure) {
5312 // Check that neither is a smi.
5313 STATIC_ASSERT(kSmiTag == 0);
5314 And(scratch1, first, Operand(second));
5315 JumpIfSmi(scratch1, failure);
5316 JumpIfNonSmisNotBothSequentialOneByteStrings(first, second, scratch1,
5317 scratch2, failure);
5318}
5319
5320
5321void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
5322 Register first, Register second, Register scratch1, Register scratch2,
5323 Label* failure) {
5324 const int kFlatOneByteStringMask =
5325 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
5326 const int kFlatOneByteStringTag =
5327 kStringTag | kOneByteStringTag | kSeqStringTag;
5328 DCHECK(kFlatOneByteStringTag <= 0xffff); // Ensure this fits 16-bit immed.
5329 andi(scratch1, first, kFlatOneByteStringMask);
5330 Branch(failure, ne, scratch1, Operand(kFlatOneByteStringTag));
5331 andi(scratch2, second, kFlatOneByteStringMask);
5332 Branch(failure, ne, scratch2, Operand(kFlatOneByteStringTag));
5333}
5334
5335
5336void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
5337 Register scratch,
5338 Label* failure) {
5339 const int kFlatOneByteStringMask =
5340 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
5341 const int kFlatOneByteStringTag =
5342 kStringTag | kOneByteStringTag | kSeqStringTag;
5343 And(scratch, type, Operand(kFlatOneByteStringMask));
5344 Branch(failure, ne, scratch, Operand(kFlatOneByteStringTag));
5345}
5346
5347
5348static const int kRegisterPassedArguments = (kMipsAbi == kN64) ? 8 : 4;
5349
5350int MacroAssembler::CalculateStackPassedWords(int num_reg_arguments,
5351 int num_double_arguments) {
5352 int stack_passed_words = 0;
5353 num_reg_arguments += 2 * num_double_arguments;
5354
5355 // O32: Up to four simple arguments are passed in registers a0..a3.
5356 // N64: Up to eight simple arguments are passed in registers a0..a7.
5357 if (num_reg_arguments > kRegisterPassedArguments) {
5358 stack_passed_words += num_reg_arguments - kRegisterPassedArguments;
5359 }
5360 stack_passed_words += kCArgSlotCount;
5361 return stack_passed_words;
5362}
5363
5364
5365void MacroAssembler::EmitSeqStringSetCharCheck(Register string,
5366 Register index,
5367 Register value,
5368 Register scratch,
5369 uint32_t encoding_mask) {
5370 Label is_object;
5371 SmiTst(string, at);
5372 Check(ne, kNonObject, at, Operand(zero_reg));
5373
5374 ld(at, FieldMemOperand(string, HeapObject::kMapOffset));
5375 lbu(at, FieldMemOperand(at, Map::kInstanceTypeOffset));
5376
5377 andi(at, at, kStringRepresentationMask | kStringEncodingMask);
5378 li(scratch, Operand(encoding_mask));
5379 Check(eq, kUnexpectedStringType, at, Operand(scratch));
5380
5381 // TODO(plind): requires Smi size check code for mips32.
5382
5383 ld(at, FieldMemOperand(string, String::kLengthOffset));
5384 Check(lt, kIndexIsTooLarge, index, Operand(at));
5385
5386 DCHECK(Smi::FromInt(0) == 0);
5387 Check(ge, kIndexIsNegative, index, Operand(zero_reg));
5388}
5389
5390
5391void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
5392 int num_double_arguments,
5393 Register scratch) {
5394 int frame_alignment = ActivationFrameAlignment();
5395
5396 // n64: Up to eight simple arguments in a0..a3, a4..a7, No argument slots.
5397 // O32: Up to four simple arguments are passed in registers a0..a3.
5398 // Those four arguments must have reserved argument slots on the stack for
5399 // mips, even though those argument slots are not normally used.
5400 // Both ABIs: Remaining arguments are pushed on the stack, above (higher
5401 // address than) the (O32) argument slots. (arg slot calculation handled by
5402 // CalculateStackPassedWords()).
5403 int stack_passed_arguments = CalculateStackPassedWords(
5404 num_reg_arguments, num_double_arguments);
5405 if (frame_alignment > kPointerSize) {
5406 // Make stack end at alignment and make room for num_arguments - 4 words
5407 // and the original value of sp.
5408 mov(scratch, sp);
5409 Dsubu(sp, sp, Operand((stack_passed_arguments + 1) * kPointerSize));
5410 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
5411 And(sp, sp, Operand(-frame_alignment));
5412 sd(scratch, MemOperand(sp, stack_passed_arguments * kPointerSize));
5413 } else {
5414 Dsubu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
5415 }
5416}
5417
5418
5419void MacroAssembler::PrepareCallCFunction(int num_reg_arguments,
5420 Register scratch) {
5421 PrepareCallCFunction(num_reg_arguments, 0, scratch);
5422}
5423
5424
5425void MacroAssembler::CallCFunction(ExternalReference function,
5426 int num_reg_arguments,
5427 int num_double_arguments) {
5428 li(t8, Operand(function));
5429 CallCFunctionHelper(t8, num_reg_arguments, num_double_arguments);
5430}
5431
5432
5433void MacroAssembler::CallCFunction(Register function,
5434 int num_reg_arguments,
5435 int num_double_arguments) {
5436 CallCFunctionHelper(function, num_reg_arguments, num_double_arguments);
5437}
5438
5439
5440void MacroAssembler::CallCFunction(ExternalReference function,
5441 int num_arguments) {
5442 CallCFunction(function, num_arguments, 0);
5443}
5444
5445
5446void MacroAssembler::CallCFunction(Register function,
5447 int num_arguments) {
5448 CallCFunction(function, num_arguments, 0);
5449}
5450
5451
5452void MacroAssembler::CallCFunctionHelper(Register function,
5453 int num_reg_arguments,
5454 int num_double_arguments) {
5455 DCHECK(has_frame());
5456 // Make sure that the stack is aligned before calling a C function unless
5457 // running in the simulator. The simulator has its own alignment check which
5458 // provides more information.
5459 // The argument stots are presumed to have been set up by
5460 // PrepareCallCFunction. The C function must be called via t9, for mips ABI.
5461
5462#if V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64
5463 if (emit_debug_code()) {
5464 int frame_alignment = base::OS::ActivationFrameAlignment();
5465 int frame_alignment_mask = frame_alignment - 1;
5466 if (frame_alignment > kPointerSize) {
5467 DCHECK(base::bits::IsPowerOfTwo32(frame_alignment));
5468 Label alignment_as_expected;
5469 And(at, sp, Operand(frame_alignment_mask));
5470 Branch(&alignment_as_expected, eq, at, Operand(zero_reg));
5471 // Don't use Check here, as it will call Runtime_Abort possibly
5472 // re-entering here.
5473 stop("Unexpected alignment in CallCFunction");
5474 bind(&alignment_as_expected);
5475 }
5476 }
5477#endif // V8_HOST_ARCH_MIPS
5478
5479 // Just call directly. The function called cannot cause a GC, or
5480 // allow preemption, so the return address in the link register
5481 // stays correct.
5482
5483 if (!function.is(t9)) {
5484 mov(t9, function);
5485 function = t9;
5486 }
5487
5488 Call(function);
5489
5490 int stack_passed_arguments = CalculateStackPassedWords(
5491 num_reg_arguments, num_double_arguments);
5492
5493 if (base::OS::ActivationFrameAlignment() > kPointerSize) {
5494 ld(sp, MemOperand(sp, stack_passed_arguments * kPointerSize));
5495 } else {
5496 Daddu(sp, sp, Operand(stack_passed_arguments * kPointerSize));
5497 }
5498}
5499
5500
5501#undef BRANCH_ARGS_CHECK
5502
5503
5504void MacroAssembler::PatchRelocatedValue(Register li_location,
5505 Register scratch,
5506 Register new_value) {
5507 lwu(scratch, MemOperand(li_location));
5508 // At this point scratch is a lui(at, ...) instruction.
5509 if (emit_debug_code()) {
5510 And(scratch, scratch, kOpcodeMask);
5511 Check(eq, kTheInstructionToPatchShouldBeALui,
5512 scratch, Operand(LUI));
5513 lwu(scratch, MemOperand(li_location));
5514 }
5515 dsrl32(t9, new_value, 0);
5516 Ins(scratch, t9, 0, kImm16Bits);
5517 sw(scratch, MemOperand(li_location));
5518
5519 lwu(scratch, MemOperand(li_location, kInstrSize));
5520 // scratch is now ori(at, ...).
5521 if (emit_debug_code()) {
5522 And(scratch, scratch, kOpcodeMask);
5523 Check(eq, kTheInstructionToPatchShouldBeAnOri,
5524 scratch, Operand(ORI));
5525 lwu(scratch, MemOperand(li_location, kInstrSize));
5526 }
5527 dsrl(t9, new_value, kImm16Bits);
5528 Ins(scratch, t9, 0, kImm16Bits);
5529 sw(scratch, MemOperand(li_location, kInstrSize));
5530
5531 lwu(scratch, MemOperand(li_location, kInstrSize * 3));
5532 // scratch is now ori(at, ...).
5533 if (emit_debug_code()) {
5534 And(scratch, scratch, kOpcodeMask);
5535 Check(eq, kTheInstructionToPatchShouldBeAnOri,
5536 scratch, Operand(ORI));
5537 lwu(scratch, MemOperand(li_location, kInstrSize * 3));
5538 }
5539
5540 Ins(scratch, new_value, 0, kImm16Bits);
5541 sw(scratch, MemOperand(li_location, kInstrSize * 3));
5542
5543 // Update the I-cache so the new lui and ori can be executed.
5544 FlushICache(li_location, 4);
5545}
5546
5547void MacroAssembler::GetRelocatedValue(Register li_location,
5548 Register value,
5549 Register scratch) {
5550 lwu(value, MemOperand(li_location));
5551 if (emit_debug_code()) {
5552 And(value, value, kOpcodeMask);
5553 Check(eq, kTheInstructionShouldBeALui,
5554 value, Operand(LUI));
5555 lwu(value, MemOperand(li_location));
5556 }
5557
5558 // value now holds a lui instruction. Extract the immediate.
5559 andi(value, value, kImm16Mask);
5560 dsll32(value, value, kImm16Bits);
5561
5562 lwu(scratch, MemOperand(li_location, kInstrSize));
5563 if (emit_debug_code()) {
5564 And(scratch, scratch, kOpcodeMask);
5565 Check(eq, kTheInstructionShouldBeAnOri,
5566 scratch, Operand(ORI));
5567 lwu(scratch, MemOperand(li_location, kInstrSize));
5568 }
5569 // "scratch" now holds an ori instruction. Extract the immediate.
5570 andi(scratch, scratch, kImm16Mask);
5571 dsll32(scratch, scratch, 0);
5572
5573 or_(value, value, scratch);
5574
5575 lwu(scratch, MemOperand(li_location, kInstrSize * 3));
5576 if (emit_debug_code()) {
5577 And(scratch, scratch, kOpcodeMask);
5578 Check(eq, kTheInstructionShouldBeAnOri,
5579 scratch, Operand(ORI));
5580 lwu(scratch, MemOperand(li_location, kInstrSize * 3));
5581 }
5582 // "scratch" now holds an ori instruction. Extract the immediate.
5583 andi(scratch, scratch, kImm16Mask);
5584 dsll(scratch, scratch, kImm16Bits);
5585
5586 or_(value, value, scratch);
5587 // Sign extend extracted address.
5588 dsra(value, value, kImm16Bits);
5589}
5590
5591
5592void MacroAssembler::CheckPageFlag(
5593 Register object,
5594 Register scratch,
5595 int mask,
5596 Condition cc,
5597 Label* condition_met) {
5598 And(scratch, object, Operand(~Page::kPageAlignmentMask));
5599 ld(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
5600 And(scratch, scratch, Operand(mask));
5601 Branch(condition_met, cc, scratch, Operand(zero_reg));
5602}
5603
5604
5605void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
5606 Register scratch,
5607 Label* if_deprecated) {
5608 if (map->CanBeDeprecated()) {
5609 li(scratch, Operand(map));
5610 ld(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
5611 And(scratch, scratch, Operand(Map::Deprecated::kMask));
5612 Branch(if_deprecated, ne, scratch, Operand(zero_reg));
5613 }
5614}
5615
5616
5617void MacroAssembler::JumpIfBlack(Register object,
5618 Register scratch0,
5619 Register scratch1,
5620 Label* on_black) {
5621 HasColor(object, scratch0, scratch1, on_black, 1, 0); // kBlackBitPattern.
5622 DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
5623}
5624
5625
5626void MacroAssembler::HasColor(Register object,
5627 Register bitmap_scratch,
5628 Register mask_scratch,
5629 Label* has_color,
5630 int first_bit,
5631 int second_bit) {
5632 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, t8));
5633 DCHECK(!AreAliased(object, bitmap_scratch, mask_scratch, t9));
5634
5635 GetMarkBits(object, bitmap_scratch, mask_scratch);
5636
5637 Label other_color;
5638 // Note that we are using a 4-byte aligned 8-byte load.
5639 Uld(t9, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
5640 And(t8, t9, Operand(mask_scratch));
5641 Branch(&other_color, first_bit == 1 ? eq : ne, t8, Operand(zero_reg));
5642 // Shift left 1 by adding.
5643 Daddu(mask_scratch, mask_scratch, Operand(mask_scratch));
5644 And(t8, t9, Operand(mask_scratch));
5645 Branch(has_color, second_bit == 1 ? ne : eq, t8, Operand(zero_reg));
5646
5647 bind(&other_color);
5648}
5649
5650
5651// Detect some, but not all, common pointer-free objects. This is used by the
5652// incremental write barrier which doesn't care about oddballs (they are always
5653// marked black immediately so this code is not hit).
5654void MacroAssembler::JumpIfDataObject(Register value,
5655 Register scratch,
5656 Label* not_data_object) {
5657 DCHECK(!AreAliased(value, scratch, t8, no_reg));
5658 Label is_data_object;
5659 ld(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
5660 LoadRoot(t8, Heap::kHeapNumberMapRootIndex);
5661 Branch(&is_data_object, eq, t8, Operand(scratch));
5662 DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
5663 DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
5664 // If it's a string and it's not a cons string then it's an object containing
5665 // no GC pointers.
5666 lbu(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
5667 And(t8, scratch, Operand(kIsIndirectStringMask | kIsNotStringMask));
5668 Branch(not_data_object, ne, t8, Operand(zero_reg));
5669 bind(&is_data_object);
5670}
5671
5672
5673void MacroAssembler::GetMarkBits(Register addr_reg,
5674 Register bitmap_reg,
5675 Register mask_reg) {
5676 DCHECK(!AreAliased(addr_reg, bitmap_reg, mask_reg, no_reg));
5677 // addr_reg is divided into fields:
5678 // |63 page base 20|19 high 8|7 shift 3|2 0|
5679 // 'high' gives the index of the cell holding color bits for the object.
5680 // 'shift' gives the offset in the cell for this object's color.
5681 And(bitmap_reg, addr_reg, Operand(~Page::kPageAlignmentMask));
5682 Ext(mask_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2);
5683 const int kLowBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
5684 Ext(t8, addr_reg, kLowBits, kPageSizeBits - kLowBits);
5685 dsll(t8, t8, Bitmap::kBytesPerCellLog2);
5686 Daddu(bitmap_reg, bitmap_reg, t8);
5687 li(t8, Operand(1));
5688 dsllv(mask_reg, t8, mask_reg);
5689}
5690
5691
5692void MacroAssembler::EnsureNotWhite(
5693 Register value,
5694 Register bitmap_scratch,
5695 Register mask_scratch,
5696 Register load_scratch,
5697 Label* value_is_white_and_not_data) {
5698 DCHECK(!AreAliased(value, bitmap_scratch, mask_scratch, t8));
5699 GetMarkBits(value, bitmap_scratch, mask_scratch);
5700
5701 // If the value is black or grey we don't need to do anything.
5702 DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
5703 DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
5704 DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
5705 DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
5706
5707 Label done;
5708
5709 // Since both black and grey have a 1 in the first position and white does
5710 // not have a 1 there we only need to check one bit.
5711 // Note that we are using a 4-byte aligned 8-byte load.
5712 Uld(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
5713 And(t8, mask_scratch, load_scratch);
5714 Branch(&done, ne, t8, Operand(zero_reg));
5715
5716 if (emit_debug_code()) {
5717 // Check for impossible bit pattern.
5718 Label ok;
5719 // sll may overflow, making the check conservative.
5720 dsll(t8, mask_scratch, 1);
5721 And(t8, load_scratch, t8);
5722 Branch(&ok, eq, t8, Operand(zero_reg));
5723 stop("Impossible marking bit pattern");
5724 bind(&ok);
5725 }
5726
5727 // Value is white. We check whether it is data that doesn't need scanning.
5728 // Currently only checks for HeapNumber and non-cons strings.
5729 Register map = load_scratch; // Holds map while checking type.
5730 Register length = load_scratch; // Holds length of object after testing type.
5731 Label is_data_object;
5732
5733 // Check for heap-number
5734 ld(map, FieldMemOperand(value, HeapObject::kMapOffset));
5735 LoadRoot(t8, Heap::kHeapNumberMapRootIndex);
5736 {
5737 Label skip;
5738 Branch(&skip, ne, t8, Operand(map));
5739 li(length, HeapNumber::kSize);
5740 Branch(&is_data_object);
5741 bind(&skip);
5742 }
5743
5744 // Check for strings.
5745 DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
5746 DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
5747 // If it's a string and it's not a cons string then it's an object containing
5748 // no GC pointers.
5749 Register instance_type = load_scratch;
5750 lbu(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
5751 And(t8, instance_type, Operand(kIsIndirectStringMask | kIsNotStringMask));
5752 Branch(value_is_white_and_not_data, ne, t8, Operand(zero_reg));
5753 // It's a non-indirect (non-cons and non-slice) string.
5754 // If it's external, the length is just ExternalString::kSize.
5755 // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
5756 // External strings are the only ones with the kExternalStringTag bit
5757 // set.
5758 DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
5759 DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
5760 And(t8, instance_type, Operand(kExternalStringTag));
5761 {
5762 Label skip;
5763 Branch(&skip, eq, t8, Operand(zero_reg));
5764 li(length, ExternalString::kSize);
5765 Branch(&is_data_object);
5766 bind(&skip);
5767 }
5768
5769 // Sequential string, either Latin1 or UC16.
5770 // For Latin1 (char-size of 1) we shift the smi tag away to get the length.
5771 // For UC16 (char-size of 2) we just leave the smi tag in place, thereby
5772 // getting the length multiplied by 2.
5773 DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4);
5774 DCHECK(kSmiTag == 0 && kSmiTagSize == 1);
5775 lw(t9, UntagSmiFieldMemOperand(value, String::kLengthOffset));
5776 And(t8, instance_type, Operand(kStringEncodingMask));
5777 {
5778 Label skip;
5779 Branch(&skip, ne, t8, Operand(zero_reg));
5780 // Adjust length for UC16.
5781 dsll(t9, t9, 1);
5782 bind(&skip);
5783 }
5784 Daddu(length, t9, Operand(SeqString::kHeaderSize + kObjectAlignmentMask));
5785 DCHECK(!length.is(t8));
5786 And(length, length, Operand(~kObjectAlignmentMask));
5787
5788 bind(&is_data_object);
5789 // Value is a data object, and it is white. Mark it black. Since we know
5790 // that the object is white we can make it black by flipping one bit.
5791 Uld(t8, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
5792 Or(t8, t8, Operand(mask_scratch));
5793 Usd(t8, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
5794
5795 And(bitmap_scratch, bitmap_scratch, Operand(~Page::kPageAlignmentMask));
5796 Uld(t8, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
5797 Daddu(t8, t8, Operand(length));
5798 Usd(t8, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
5799
5800 bind(&done);
5801}
5802
5803
5804void MacroAssembler::LoadInstanceDescriptors(Register map,
5805 Register descriptors) {
5806 ld(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
5807}
5808
5809
5810void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
5811 ld(dst, FieldMemOperand(map, Map::kBitField3Offset));
5812 DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
5813}
5814
5815
5816void MacroAssembler::EnumLength(Register dst, Register map) {
5817 STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
5818 ld(dst, FieldMemOperand(map, Map::kBitField3Offset));
5819 And(dst, dst, Operand(Map::EnumLengthBits::kMask));
5820 SmiTag(dst);
5821}
5822
5823
5824void MacroAssembler::CheckEnumCache(Register null_value, Label* call_runtime) {
5825 Register empty_fixed_array_value = a6;
5826 LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
5827 Label next, start;
5828 mov(a2, a0);
5829
5830 // Check if the enum length field is properly initialized, indicating that
5831 // there is an enum cache.
5832 ld(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
5833
5834 EnumLength(a3, a1);
5835 Branch(
5836 call_runtime, eq, a3, Operand(Smi::FromInt(kInvalidEnumCacheSentinel)));
5837
5838 jmp(&start);
5839
5840 bind(&next);
5841 ld(a1, FieldMemOperand(a2, HeapObject::kMapOffset));
5842
5843 // For all objects but the receiver, check that the cache is empty.
5844 EnumLength(a3, a1);
5845 Branch(call_runtime, ne, a3, Operand(Smi::FromInt(0)));
5846
5847 bind(&start);
5848
5849 // Check that there are no elements. Register a2 contains the current JS
5850 // object we've reached through the prototype chain.
5851 Label no_elements;
5852 ld(a2, FieldMemOperand(a2, JSObject::kElementsOffset));
5853 Branch(&no_elements, eq, a2, Operand(empty_fixed_array_value));
5854
5855 // Second chance, the object may be using the empty slow element dictionary.
5856 LoadRoot(at, Heap::kEmptySlowElementDictionaryRootIndex);
5857 Branch(call_runtime, ne, a2, Operand(at));
5858
5859 bind(&no_elements);
5860 ld(a2, FieldMemOperand(a1, Map::kPrototypeOffset));
5861 Branch(&next, ne, a2, Operand(null_value));
5862}
5863
5864
5865void MacroAssembler::ClampUint8(Register output_reg, Register input_reg) {
5866 DCHECK(!output_reg.is(input_reg));
5867 Label done;
5868 li(output_reg, Operand(255));
5869 // Normal branch: nop in delay slot.
5870 Branch(&done, gt, input_reg, Operand(output_reg));
5871 // Use delay slot in this branch.
5872 Branch(USE_DELAY_SLOT, &done, lt, input_reg, Operand(zero_reg));
5873 mov(output_reg, zero_reg); // In delay slot.
5874 mov(output_reg, input_reg); // Value is in range 0..255.
5875 bind(&done);
5876}
5877
5878
5879void MacroAssembler::ClampDoubleToUint8(Register result_reg,
5880 DoubleRegister input_reg,
5881 DoubleRegister temp_double_reg) {
5882 Label above_zero;
5883 Label done;
5884 Label in_bounds;
5885
5886 Move(temp_double_reg, 0.0);
5887 BranchF(&above_zero, NULL, gt, input_reg, temp_double_reg);
5888
5889 // Double value is less than zero, NaN or Inf, return 0.
5890 mov(result_reg, zero_reg);
5891 Branch(&done);
5892
5893 // Double value is >= 255, return 255.
5894 bind(&above_zero);
5895 Move(temp_double_reg, 255.0);
5896 BranchF(&in_bounds, NULL, le, input_reg, temp_double_reg);
5897 li(result_reg, Operand(255));
5898 Branch(&done);
5899
5900 // In 0-255 range, round and truncate.
5901 bind(&in_bounds);
5902 cvt_w_d(temp_double_reg, input_reg);
5903 mfc1(result_reg, temp_double_reg);
5904 bind(&done);
5905}
5906
5907
5908void MacroAssembler::TestJSArrayForAllocationMemento(
5909 Register receiver_reg,
5910 Register scratch_reg,
5911 Label* no_memento_found,
5912 Condition cond,
5913 Label* allocation_memento_present) {
5914 ExternalReference new_space_start =
5915 ExternalReference::new_space_start(isolate());
5916 ExternalReference new_space_allocation_top =
5917 ExternalReference::new_space_allocation_top_address(isolate());
5918 Daddu(scratch_reg, receiver_reg,
5919 Operand(JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag));
5920 Branch(no_memento_found, lt, scratch_reg, Operand(new_space_start));
5921 li(at, Operand(new_space_allocation_top));
5922 ld(at, MemOperand(at));
5923 Branch(no_memento_found, gt, scratch_reg, Operand(at));
5924 ld(scratch_reg, MemOperand(scratch_reg, -AllocationMemento::kSize));
5925 if (allocation_memento_present) {
5926 Branch(allocation_memento_present, cond, scratch_reg,
5927 Operand(isolate()->factory()->allocation_memento_map()));
5928 }
5929}
5930
5931
5932Register GetRegisterThatIsNotOneOf(Register reg1,
5933 Register reg2,
5934 Register reg3,
5935 Register reg4,
5936 Register reg5,
5937 Register reg6) {
5938 RegList regs = 0;
5939 if (reg1.is_valid()) regs |= reg1.bit();
5940 if (reg2.is_valid()) regs |= reg2.bit();
5941 if (reg3.is_valid()) regs |= reg3.bit();
5942 if (reg4.is_valid()) regs |= reg4.bit();
5943 if (reg5.is_valid()) regs |= reg5.bit();
5944 if (reg6.is_valid()) regs |= reg6.bit();
5945
5946 for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
5947 Register candidate = Register::FromAllocationIndex(i);
5948 if (regs & candidate.bit()) continue;
5949 return candidate;
5950 }
5951 UNREACHABLE();
5952 return no_reg;
5953}
5954
5955
5956void MacroAssembler::JumpIfDictionaryInPrototypeChain(
5957 Register object,
5958 Register scratch0,
5959 Register scratch1,
5960 Label* found) {
5961 DCHECK(!scratch1.is(scratch0));
5962 Factory* factory = isolate()->factory();
5963 Register current = scratch0;
5964 Label loop_again;
5965
5966 // Scratch contained elements pointer.
5967 Move(current, object);
5968
5969 // Loop based on the map going up the prototype chain.
5970 bind(&loop_again);
5971 ld(current, FieldMemOperand(current, HeapObject::kMapOffset));
5972 lb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
5973 DecodeField<Map::ElementsKindBits>(scratch1);
5974 Branch(found, eq, scratch1, Operand(DICTIONARY_ELEMENTS));
5975 ld(current, FieldMemOperand(current, Map::kPrototypeOffset));
5976 Branch(&loop_again, ne, current, Operand(factory->null_value()));
5977}
5978
5979
5980bool AreAliased(Register reg1,
5981 Register reg2,
5982 Register reg3,
5983 Register reg4,
5984 Register reg5,
5985 Register reg6,
5986 Register reg7,
5987 Register reg8) {
5988 int n_of_valid_regs = reg1.is_valid() + reg2.is_valid() +
5989 reg3.is_valid() + reg4.is_valid() + reg5.is_valid() + reg6.is_valid() +
5990 reg7.is_valid() + reg8.is_valid();
5991
5992 RegList regs = 0;
5993 if (reg1.is_valid()) regs |= reg1.bit();
5994 if (reg2.is_valid()) regs |= reg2.bit();
5995 if (reg3.is_valid()) regs |= reg3.bit();
5996 if (reg4.is_valid()) regs |= reg4.bit();
5997 if (reg5.is_valid()) regs |= reg5.bit();
5998 if (reg6.is_valid()) regs |= reg6.bit();
5999 if (reg7.is_valid()) regs |= reg7.bit();
6000 if (reg8.is_valid()) regs |= reg8.bit();
6001 int n_of_non_aliasing_regs = NumRegs(regs);
6002
6003 return n_of_valid_regs != n_of_non_aliasing_regs;
6004}
6005
6006
6007CodePatcher::CodePatcher(byte* address,
6008 int instructions,
6009 FlushICache flush_cache)
6010 : address_(address),
6011 size_(instructions * Assembler::kInstrSize),
6012 masm_(NULL, address, size_ + Assembler::kGap),
6013 flush_cache_(flush_cache) {
6014 // Create a new macro assembler pointing to the address of the code to patch.
6015 // The size is adjusted with kGap on order for the assembler to generate size
6016 // bytes of instructions without failing with buffer size constraints.
6017 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
6018}
6019
6020
6021CodePatcher::~CodePatcher() {
6022 // Indicate that code has changed.
6023 if (flush_cache_ == FLUSH) {
6024 CpuFeatures::FlushICache(address_, size_);
6025 }
6026 // Check that the code was patched as expected.
6027 DCHECK(masm_.pc_ == address_ + size_);
6028 DCHECK(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap);
6029}
6030
6031
6032void CodePatcher::Emit(Instr instr) {
6033 masm()->emit(instr);
6034}
6035
6036
6037void CodePatcher::Emit(Address addr) {
6038 // masm()->emit(reinterpret_cast<Instr>(addr));
6039}
6040
6041
6042void CodePatcher::ChangeBranchCondition(Condition cond) {
6043 Instr instr = Assembler::instr_at(masm_.pc_);
6044 DCHECK(Assembler::IsBranch(instr));
6045 uint32_t opcode = Assembler::GetOpcodeField(instr);
6046 // Currently only the 'eq' and 'ne' cond values are supported and the simple
6047 // branch instructions (with opcode being the branch type).
6048 // There are some special cases (see Assembler::IsBranch()) so extending this
6049 // would be tricky.
6050 DCHECK(opcode == BEQ ||
6051 opcode == BNE ||
6052 opcode == BLEZ ||
6053 opcode == BGTZ ||
6054 opcode == BEQL ||
6055 opcode == BNEL ||
6056 opcode == BLEZL ||
6057 opcode == BGTZL);
6058 opcode = (cond == eq) ? BEQ : BNE;
6059 instr = (instr & ~kOpcodeMask) | opcode;
6060 masm_.emit(instr);
6061}
6062
6063
6064void MacroAssembler::TruncatingDiv(Register result,
6065 Register dividend,
6066 int32_t divisor) {
6067 DCHECK(!dividend.is(result));
6068 DCHECK(!dividend.is(at));
6069 DCHECK(!result.is(at));
6070 base::MagicNumbersForDivision<uint32_t> mag =
6071 base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
6072 li(at, Operand(mag.multiplier));
6073 Mulh(result, dividend, Operand(at));
6074 bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
6075 if (divisor > 0 && neg) {
6076 Addu(result, result, Operand(dividend));
6077 }
6078 if (divisor < 0 && !neg && mag.multiplier > 0) {
6079 Subu(result, result, Operand(dividend));
6080 }
6081 if (mag.shift > 0) sra(result, result, mag.shift);
6082 srl(at, dividend, 31);
6083 Addu(result, result, Operand(at));
6084}
6085
6086
6087} } // namespace v8::internal
6088
6089#endif // V8_TARGET_ARCH_MIPS64