1 // 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.
5 #ifndef V8_MIPS_MACRO_ASSEMBLER_MIPS_H_
6 #define V8_MIPS_MACRO_ASSEMBLER_MIPS_H_
8 #include "src/assembler.h"
9 #include "src/globals.h"
10 #include "src/mips/assembler-mips.h"
15 // Give alias names to registers for calling conventions.
16 const Register kReturnRegister0 = {kRegister_v0_Code};
17 const Register kReturnRegister1 = {kRegister_v1_Code};
18 const Register kJSFunctionRegister = {kRegister_a1_Code};
19 const Register kContextRegister = {Register::kCpRegister};
20 const Register kInterpreterAccumulatorRegister = {kRegister_v0_Code};
21 const Register kInterpreterRegisterFileRegister = {kRegister_t3_Code};
22 const Register kInterpreterBytecodeOffsetRegister = {kRegister_t4_Code};
23 const Register kInterpreterBytecodeArrayRegister = {kRegister_t5_Code};
24 const Register kInterpreterDispatchTableRegister = {kRegister_t6_Code};
25 const Register kRuntimeCallFunctionRegister = {kRegister_a1_Code};
26 const Register kRuntimeCallArgCountRegister = {kRegister_a0_Code};
28 // Forward declaration.
31 // Reserved Register Usage Summary.
33 // Registers t8, t9, and at are reserved for use by the MacroAssembler.
35 // The programmer should know that the MacroAssembler may clobber these three,
36 // but won't touch other registers except in special cases.
38 // Per the MIPS ABI, register t9 must be used for indirect function call
39 // via 'jalr t9' or 'jr t9' instructions. This is relied upon by gcc when
40 // trying to update gp register for position-independent-code. Whenever
41 // MIPS generated code calls C code, it must be via t9 register.
44 // Flags used for LeaveExitFrame function.
45 enum LeaveExitFrameMode {
47 NO_EMIT_RETURN = false
50 // Flags used for AllocateHeapNumber
58 // Flags used for the ObjectToDoubleFPURegister function.
59 enum ObjectToDoubleFlags {
61 NO_OBJECT_TO_DOUBLE_FLAGS = 0,
62 // Object is known to be a non smi.
63 OBJECT_NOT_SMI = 1 << 0,
64 // Don't load NaNs or infinities, branch to the non number case instead.
65 AVOID_NANS_AND_INFINITIES = 1 << 1
68 // Allow programmer to use Branch Delay Slot of Branches, Jumps, Calls.
69 enum BranchDelaySlot {
74 // Flags used for the li macro-assembler function.
76 // If the constant value can be represented in just 16 bits, then
77 // optimize the li to use a single instruction, rather than lui/ori pair.
79 // Always use 2 instructions (lui/ori pair), even if the constant could
80 // be loaded with just one, so that this value is patchable later.
85 enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
86 enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
87 enum PointersToHereCheck {
88 kPointersToHereMaybeInteresting,
89 kPointersToHereAreAlwaysInteresting
91 enum RAStatus { kRAHasNotBeenSaved, kRAHasBeenSaved };
93 Register GetRegisterThatIsNotOneOf(Register reg1,
94 Register reg2 = no_reg,
95 Register reg3 = no_reg,
96 Register reg4 = no_reg,
97 Register reg5 = no_reg,
98 Register reg6 = no_reg);
100 bool AreAliased(Register reg1,
102 Register reg3 = no_reg,
103 Register reg4 = no_reg,
104 Register reg5 = no_reg,
105 Register reg6 = no_reg,
106 Register reg7 = no_reg,
107 Register reg8 = no_reg);
110 // -----------------------------------------------------------------------------
111 // Static helper functions.
113 inline MemOperand ContextOperand(Register context, int index) {
114 return MemOperand(context, Context::SlotOffset(index));
118 inline MemOperand GlobalObjectOperand() {
119 return ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX);
123 // Generate a MemOperand for loading a field from an object.
124 inline MemOperand FieldMemOperand(Register object, int offset) {
125 return MemOperand(object, offset - kHeapObjectTag);
129 // Generate a MemOperand for storing arguments 5..N on the stack
130 // when calling CallCFunction().
131 inline MemOperand CFunctionArgumentOperand(int index) {
132 DCHECK(index > kCArgSlotCount);
133 // Argument 5 takes the slot just past the four Arg-slots.
134 int offset = (index - 5) * kPointerSize + kCArgsSlotsSize;
135 return MemOperand(sp, offset);
139 // MacroAssembler implements a collection of frequently used macros.
140 class MacroAssembler: public Assembler {
142 // The isolate parameter can be NULL if the macro assembler should
143 // not use isolate-dependent functionality. In this case, it's the
144 // responsibility of the caller to never invoke such function on the
146 MacroAssembler(Isolate* isolate, void* buffer, int size);
149 #define COND_TYPED_ARGS Condition cond, Register r1, const Operand& r2
150 #define COND_ARGS cond, r1, r2
152 // Cases when relocation is not needed.
153 #define DECLARE_NORELOC_PROTOTYPE(Name, target_type) \
154 void Name(target_type target, BranchDelaySlot bd = PROTECT); \
155 inline void Name(BranchDelaySlot bd, target_type target) { \
158 void Name(target_type target, \
160 BranchDelaySlot bd = PROTECT); \
161 inline void Name(BranchDelaySlot bd, \
162 target_type target, \
164 Name(target, COND_ARGS, bd); \
167 #define DECLARE_BRANCH_PROTOTYPES(Name) \
168 DECLARE_NORELOC_PROTOTYPE(Name, Label*) \
169 DECLARE_NORELOC_PROTOTYPE(Name, int16_t)
171 DECLARE_BRANCH_PROTOTYPES(Branch)
172 DECLARE_BRANCH_PROTOTYPES(BranchAndLink)
173 DECLARE_BRANCH_PROTOTYPES(BranchShort)
175 #undef DECLARE_BRANCH_PROTOTYPES
176 #undef COND_TYPED_ARGS
180 // Jump, Call, and Ret pseudo instructions implementing inter-working.
181 #define COND_ARGS Condition cond = al, Register rs = zero_reg, \
182 const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
184 void Jump(Register target, COND_ARGS);
185 void Jump(intptr_t target, RelocInfo::Mode rmode, COND_ARGS);
186 void Jump(Address target, RelocInfo::Mode rmode, COND_ARGS);
187 void Jump(Handle<Code> code, RelocInfo::Mode rmode, COND_ARGS);
188 static int CallSize(Register target, COND_ARGS);
189 void Call(Register target, COND_ARGS);
190 static int CallSize(Address target, RelocInfo::Mode rmode, COND_ARGS);
191 void Call(Address target, RelocInfo::Mode rmode, COND_ARGS);
192 int CallSize(Handle<Code> code,
193 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
194 TypeFeedbackId ast_id = TypeFeedbackId::None(),
196 void Call(Handle<Code> code,
197 RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
198 TypeFeedbackId ast_id = TypeFeedbackId::None(),
201 inline void Ret(BranchDelaySlot bd, Condition cond = al,
202 Register rs = zero_reg, const Operand& rt = Operand(zero_reg)) {
203 Ret(cond, rs, rt, bd);
206 void Branch(Label* L,
209 Heap::RootListIndex index,
210 BranchDelaySlot bdslot = PROTECT);
214 // Emit code to discard a non-negative number of pointer-sized elements
215 // from the stack, clobbering only the sp register.
217 Condition cond = cc_always,
218 Register reg = no_reg,
219 const Operand& op = Operand(no_reg));
221 // Trivial case of DropAndRet that utilizes the delay slot and only emits
223 void DropAndRet(int drop);
225 void DropAndRet(int drop,
230 // Swap two registers. If the scratch register is omitted then a slightly
231 // less efficient form using xor instead of mov is emitted.
232 void Swap(Register reg1, Register reg2, Register scratch = no_reg);
234 void Call(Label* target);
236 inline void Move(Register dst, Register src) {
242 inline void Move(FPURegister dst, FPURegister src) {
248 inline void Move(Register dst_low, Register dst_high, FPURegister src) {
250 Mfhc1(dst_high, src);
253 inline void FmoveHigh(Register dst_high, FPURegister src) {
254 Mfhc1(dst_high, src);
257 inline void FmoveHigh(FPURegister dst, Register src_high) {
258 Mthc1(src_high, dst);
261 inline void FmoveLow(Register dst_low, FPURegister src) {
265 void FmoveLow(FPURegister dst, Register src_low);
267 inline void Move(FPURegister dst, Register src_low, Register src_high) {
269 Mthc1(src_high, dst);
272 void Move(FPURegister dst, float imm);
273 void Move(FPURegister dst, double imm);
276 void Movz(Register rd, Register rs, Register rt);
277 void Movn(Register rd, Register rs, Register rt);
278 void Movt(Register rd, Register rs, uint16_t cc = 0);
279 void Movf(Register rd, Register rs, uint16_t cc = 0);
281 void Clz(Register rd, Register rs);
283 // Jump unconditionally to given label.
284 // We NEED a nop in the branch delay slot, as it used by v8, for example in
285 // CodeGenerator::ProcessDeferred().
286 // Currently the branch delay slot is filled by the MacroAssembler.
287 // Use rather b(Label) for code generation.
292 void Load(Register dst, const MemOperand& src, Representation r);
293 void Store(Register src, const MemOperand& dst, Representation r);
295 // Load an object from the root table.
296 void LoadRoot(Register destination,
297 Heap::RootListIndex index);
298 void LoadRoot(Register destination,
299 Heap::RootListIndex index,
300 Condition cond, Register src1, const Operand& src2);
302 // Store an object to the root table.
303 void StoreRoot(Register source,
304 Heap::RootListIndex index);
305 void StoreRoot(Register source,
306 Heap::RootListIndex index,
307 Condition cond, Register src1, const Operand& src2);
309 // ---------------------------------------------------------------------------
312 void IncrementalMarkingRecordWriteHelper(Register object,
316 enum RememberedSetFinalAction {
322 // Record in the remembered set the fact that we have a pointer to new space
323 // at the address pointed to by the addr register. Only works if addr is not
325 void RememberedSetHelper(Register object, // Used for debug code.
328 SaveFPRegsMode save_fp,
329 RememberedSetFinalAction and_then);
331 void CheckPageFlag(Register object,
335 Label* condition_met);
337 // Check if object is in new space. Jumps if the object is not in new space.
338 // The register scratch can be object itself, but it will be clobbered.
339 void JumpIfNotInNewSpace(Register object,
342 InNewSpace(object, scratch, ne, branch);
345 // Check if object is in new space. Jumps if the object is in new space.
346 // The register scratch can be object itself, but scratch will be clobbered.
347 void JumpIfInNewSpace(Register object,
350 InNewSpace(object, scratch, eq, branch);
353 // Check if an object has a given incremental marking color.
354 void HasColor(Register object,
361 void JumpIfBlack(Register object,
366 // Checks the color of an object. If the object is already grey or black
367 // then we just fall through, since it is already live. If it is white and
368 // we can determine that it doesn't need to be scanned, then we just mark it
369 // black and fall through. For the rest we jump to the label so the
370 // incremental marker can fix its assumptions.
371 void EnsureNotWhite(Register object,
375 Label* object_is_white_and_not_data);
377 // Detects conservatively whether an object is data-only, i.e. it does need to
378 // be scanned by the garbage collector.
379 void JumpIfDataObject(Register value,
381 Label* not_data_object);
383 // Notify the garbage collector that we wrote a pointer into an object.
384 // |object| is the object being stored into, |value| is the object being
385 // stored. value and scratch registers are clobbered by the operation.
386 // The offset is the offset from the start of the object, not the offset from
387 // the tagged HeapObject pointer. For use with FieldOperand(reg, off).
388 void RecordWriteField(
394 SaveFPRegsMode save_fp,
395 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
396 SmiCheck smi_check = INLINE_SMI_CHECK,
397 PointersToHereCheck pointers_to_here_check_for_value =
398 kPointersToHereMaybeInteresting);
400 // As above, but the offset has the tag presubtracted. For use with
401 // MemOperand(reg, off).
402 inline void RecordWriteContextSlot(
408 SaveFPRegsMode save_fp,
409 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
410 SmiCheck smi_check = INLINE_SMI_CHECK,
411 PointersToHereCheck pointers_to_here_check_for_value =
412 kPointersToHereMaybeInteresting) {
413 RecordWriteField(context,
414 offset + kHeapObjectTag,
419 remembered_set_action,
421 pointers_to_here_check_for_value);
424 void RecordWriteForMap(
429 SaveFPRegsMode save_fp);
431 // For a given |object| notify the garbage collector that the slot |address|
432 // has been written. |value| is the object being stored. The value and
433 // address registers are clobbered by the operation.
439 SaveFPRegsMode save_fp,
440 RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
441 SmiCheck smi_check = INLINE_SMI_CHECK,
442 PointersToHereCheck pointers_to_here_check_for_value =
443 kPointersToHereMaybeInteresting);
446 // ---------------------------------------------------------------------------
447 // Inline caching support.
449 // Generate code for checking access rights - used for security checks
450 // on access to global objects across environments. The holder register
451 // is left untouched, whereas both scratch registers are clobbered.
452 void CheckAccessGlobalProxy(Register holder_reg,
456 void GetNumberHash(Register reg0, Register scratch);
458 void LoadFromNumberDictionary(Label* miss,
467 inline void MarkCode(NopMarkerTypes type) {
471 // Check if the given instruction is a 'type' marker.
472 // i.e. check if it is a sll zero_reg, zero_reg, <type> (referenced as
473 // nop(type)). These instructions are generated to mark special location in
474 // the code, like some special IC code.
475 static inline bool IsMarkedCode(Instr instr, int type) {
476 DCHECK((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER));
477 return IsNop(instr, type);
481 static inline int GetCodeMarker(Instr instr) {
482 uint32_t opcode = ((instr & kOpcodeMask));
483 uint32_t rt = ((instr & kRtFieldMask) >> kRtShift);
484 uint32_t rs = ((instr & kRsFieldMask) >> kRsShift);
485 uint32_t sa = ((instr & kSaFieldMask) >> kSaShift);
487 // Return <n> if we have a sll zero_reg, zero_reg, n
489 bool sllzz = (opcode == SLL &&
490 rt == static_cast<uint32_t>(ToNumber(zero_reg)) &&
491 rs == static_cast<uint32_t>(ToNumber(zero_reg)));
493 (sllzz && FIRST_IC_MARKER <= sa && sa < LAST_CODE_MARKER) ? sa : -1;
494 DCHECK((type == -1) ||
495 ((FIRST_IC_MARKER <= type) && (type < LAST_CODE_MARKER)));
501 // ---------------------------------------------------------------------------
502 // Allocation support.
504 // Allocate an object in new space or old space. The object_size is
505 // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS
506 // is passed. If the space is exhausted control continues at the gc_required
507 // label. The allocated object is returned in result. If the flag
508 // tag_allocated_object is true the result is tagged as as a heap object.
509 // All registers are clobbered also when control continues at the gc_required
511 void Allocate(int object_size,
516 AllocationFlags flags);
518 void Allocate(Register object_size,
523 AllocationFlags flags);
525 void AllocateTwoByteString(Register result,
531 void AllocateOneByteString(Register result, Register length,
532 Register scratch1, Register scratch2,
533 Register scratch3, Label* gc_required);
534 void AllocateTwoByteConsString(Register result,
539 void AllocateOneByteConsString(Register result, Register length,
540 Register scratch1, Register scratch2,
542 void AllocateTwoByteSlicedString(Register result,
547 void AllocateOneByteSlicedString(Register result, Register length,
548 Register scratch1, Register scratch2,
551 // Allocates a heap number or jumps to the gc_required label if the young
552 // space is full and a scavenge is needed. All registers are clobbered also
553 // when control continues at the gc_required label.
554 void AllocateHeapNumber(Register result,
557 Register heap_number_map,
559 TaggingMode tagging_mode = TAG_RESULT,
560 MutableMode mode = IMMUTABLE);
561 void AllocateHeapNumberWithValue(Register result,
567 // ---------------------------------------------------------------------------
568 // Instruction macros.
570 #define DEFINE_INSTRUCTION(instr) \
571 void instr(Register rd, Register rs, const Operand& rt); \
572 void instr(Register rd, Register rs, Register rt) { \
573 instr(rd, rs, Operand(rt)); \
575 void instr(Register rs, Register rt, int32_t j) { \
576 instr(rs, rt, Operand(j)); \
579 #define DEFINE_INSTRUCTION2(instr) \
580 void instr(Register rs, const Operand& rt); \
581 void instr(Register rs, Register rt) { \
582 instr(rs, Operand(rt)); \
584 void instr(Register rs, int32_t j) { \
585 instr(rs, Operand(j)); \
588 #define DEFINE_INSTRUCTION3(instr) \
589 void instr(Register rd_hi, Register rd_lo, Register rs, const Operand& rt); \
590 void instr(Register rd_hi, Register rd_lo, Register rs, Register rt) { \
591 instr(rd_hi, rd_lo, rs, Operand(rt)); \
593 void instr(Register rd_hi, Register rd_lo, Register rs, int32_t j) { \
594 instr(rd_hi, rd_lo, rs, Operand(j)); \
597 DEFINE_INSTRUCTION(Addu);
598 DEFINE_INSTRUCTION(Subu);
599 DEFINE_INSTRUCTION(Mul);
600 DEFINE_INSTRUCTION(Div);
601 DEFINE_INSTRUCTION(Divu);
602 DEFINE_INSTRUCTION(Mod);
603 DEFINE_INSTRUCTION(Modu);
604 DEFINE_INSTRUCTION(Mulh);
605 DEFINE_INSTRUCTION2(Mult);
606 DEFINE_INSTRUCTION(Mulhu);
607 DEFINE_INSTRUCTION2(Multu);
608 DEFINE_INSTRUCTION2(Div);
609 DEFINE_INSTRUCTION2(Divu);
611 DEFINE_INSTRUCTION3(Div);
612 DEFINE_INSTRUCTION3(Mul);
614 DEFINE_INSTRUCTION(And);
615 DEFINE_INSTRUCTION(Or);
616 DEFINE_INSTRUCTION(Xor);
617 DEFINE_INSTRUCTION(Nor);
618 DEFINE_INSTRUCTION2(Neg);
620 DEFINE_INSTRUCTION(Slt);
621 DEFINE_INSTRUCTION(Sltu);
623 // MIPS32 R2 instruction macro.
624 DEFINE_INSTRUCTION(Ror);
626 #undef DEFINE_INSTRUCTION
627 #undef DEFINE_INSTRUCTION2
629 void Pref(int32_t hint, const MemOperand& rs);
632 // ---------------------------------------------------------------------------
633 // Pseudo-instructions.
635 void mov(Register rd, Register rt) { or_(rd, rt, zero_reg); }
637 void Ulw(Register rd, const MemOperand& rs);
638 void Usw(Register rd, const MemOperand& rs);
640 // Load int32 in the rd register.
641 void li(Register rd, Operand j, LiFlags mode = OPTIMIZE_SIZE);
642 inline void li(Register rd, int32_t j, LiFlags mode = OPTIMIZE_SIZE) {
643 li(rd, Operand(j), mode);
645 void li(Register dst, Handle<Object> value, LiFlags mode = OPTIMIZE_SIZE);
647 // Push multiple registers on the stack.
648 // Registers are saved in numerical order, with higher numbered registers
649 // saved in higher memory addresses.
650 void MultiPush(RegList regs);
651 void MultiPushReversed(RegList regs);
653 void MultiPushFPU(RegList regs);
654 void MultiPushReversedFPU(RegList regs);
656 void push(Register src) {
657 Addu(sp, sp, Operand(-kPointerSize));
658 sw(src, MemOperand(sp, 0));
660 void Push(Register src) { push(src); }
663 void Push(Handle<Object> handle);
664 void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
666 // Push two registers. Pushes leftmost register first (to highest address).
667 void Push(Register src1, Register src2) {
668 Subu(sp, sp, Operand(2 * kPointerSize));
669 sw(src1, MemOperand(sp, 1 * kPointerSize));
670 sw(src2, MemOperand(sp, 0 * kPointerSize));
673 // Push three registers. Pushes leftmost register first (to highest address).
674 void Push(Register src1, Register src2, Register src3) {
675 Subu(sp, sp, Operand(3 * kPointerSize));
676 sw(src1, MemOperand(sp, 2 * kPointerSize));
677 sw(src2, MemOperand(sp, 1 * kPointerSize));
678 sw(src3, MemOperand(sp, 0 * kPointerSize));
681 // Push four registers. Pushes leftmost register first (to highest address).
682 void Push(Register src1, Register src2, Register src3, Register src4) {
683 Subu(sp, sp, Operand(4 * kPointerSize));
684 sw(src1, MemOperand(sp, 3 * kPointerSize));
685 sw(src2, MemOperand(sp, 2 * kPointerSize));
686 sw(src3, MemOperand(sp, 1 * kPointerSize));
687 sw(src4, MemOperand(sp, 0 * kPointerSize));
690 // Push five registers. Pushes leftmost register first (to highest address).
691 void Push(Register src1, Register src2, Register src3, Register src4,
693 Subu(sp, sp, Operand(5 * kPointerSize));
694 sw(src1, MemOperand(sp, 4 * kPointerSize));
695 sw(src2, MemOperand(sp, 3 * kPointerSize));
696 sw(src3, MemOperand(sp, 2 * kPointerSize));
697 sw(src4, MemOperand(sp, 1 * kPointerSize));
698 sw(src5, MemOperand(sp, 0 * kPointerSize));
701 void Push(Register src, Condition cond, Register tst1, Register tst2) {
702 // Since we don't have conditional execution we use a Branch.
703 Branch(3, cond, tst1, Operand(tst2));
704 Subu(sp, sp, Operand(kPointerSize));
705 sw(src, MemOperand(sp, 0));
708 // Pops multiple values from the stack and load them in the
709 // registers specified in regs. Pop order is the opposite as in MultiPush.
710 void MultiPop(RegList regs);
711 void MultiPopReversed(RegList regs);
713 void MultiPopFPU(RegList regs);
714 void MultiPopReversedFPU(RegList regs);
716 void pop(Register dst) {
717 lw(dst, MemOperand(sp, 0));
718 Addu(sp, sp, Operand(kPointerSize));
720 void Pop(Register dst) { pop(dst); }
722 // Pop two registers. Pops rightmost register first (from lower address).
723 void Pop(Register src1, Register src2) {
724 DCHECK(!src1.is(src2));
725 lw(src2, MemOperand(sp, 0 * kPointerSize));
726 lw(src1, MemOperand(sp, 1 * kPointerSize));
727 Addu(sp, sp, 2 * kPointerSize);
730 // Pop three registers. Pops rightmost register first (from lower address).
731 void Pop(Register src1, Register src2, Register src3) {
732 lw(src3, MemOperand(sp, 0 * kPointerSize));
733 lw(src2, MemOperand(sp, 1 * kPointerSize));
734 lw(src1, MemOperand(sp, 2 * kPointerSize));
735 Addu(sp, sp, 3 * kPointerSize);
738 void Pop(uint32_t count = 1) {
739 Addu(sp, sp, Operand(count * kPointerSize));
742 // Push and pop the registers that can hold pointers, as defined by the
743 // RegList constant kSafepointSavedRegisters.
744 void PushSafepointRegisters();
745 void PopSafepointRegisters();
746 // Store value in register src in the safepoint stack slot for
748 void StoreToSafepointRegisterSlot(Register src, Register dst);
749 // Load the value of the src register from its safepoint stack slot
750 // into register dst.
751 void LoadFromSafepointRegisterSlot(Register dst, Register src);
753 // Flush the I-cache from asm code. You should use CpuFeatures::FlushICache
755 // Does not handle errors.
756 void FlushICache(Register address, unsigned instructions);
758 // MIPS32 R2 instruction macro.
759 void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
760 void Ext(Register rt, Register rs, uint16_t pos, uint16_t size);
762 // ---------------------------------------------------------------------------
763 // FPU macros. These do not handle special cases like NaN or +- inf.
765 // Convert unsigned word to double.
766 void Cvt_d_uw(FPURegister fd, FPURegister fs, FPURegister scratch);
767 void Cvt_d_uw(FPURegister fd, Register rs, FPURegister scratch);
769 // Convert double to unsigned word.
770 void Trunc_uw_d(FPURegister fd, FPURegister fs, FPURegister scratch);
771 void Trunc_uw_d(FPURegister fd, Register rs, FPURegister scratch);
773 void Trunc_w_d(FPURegister fd, FPURegister fs);
774 void Round_w_d(FPURegister fd, FPURegister fs);
775 void Floor_w_d(FPURegister fd, FPURegister fs);
776 void Ceil_w_d(FPURegister fd, FPURegister fs);
778 // FP32 mode: Move the general purpose register into
779 // the high part of the double-register pair.
780 // FP64 mode: Move the general-purpose register into
781 // the higher 32 bits of the 64-bit coprocessor register,
782 // while leaving the low bits unchanged.
783 void Mthc1(Register rt, FPURegister fs);
785 // FP32 mode: move the high part of the double-register pair into
786 // general purpose register.
787 // FP64 mode: Move the higher 32 bits of the 64-bit coprocessor register into
788 // general-purpose register.
789 void Mfhc1(Register rt, FPURegister fs);
791 // Wrapper functions for the different cmp/branch types.
792 inline void BranchF32(Label* target, Label* nan, Condition cc,
793 FPURegister cmp1, FPURegister cmp2,
794 BranchDelaySlot bd = PROTECT) {
795 BranchFCommon(S, target, nan, cc, cmp1, cmp2, bd);
798 inline void BranchF64(Label* target, Label* nan, Condition cc,
799 FPURegister cmp1, FPURegister cmp2,
800 BranchDelaySlot bd = PROTECT) {
801 BranchFCommon(D, target, nan, cc, cmp1, cmp2, bd);
804 // Alternate (inline) version for better readability with USE_DELAY_SLOT.
805 inline void BranchF64(BranchDelaySlot bd, Label* target, Label* nan,
806 Condition cc, FPURegister cmp1, FPURegister cmp2) {
807 BranchF64(target, nan, cc, cmp1, cmp2, bd);
810 inline void BranchF32(BranchDelaySlot bd, Label* target, Label* nan,
811 Condition cc, FPURegister cmp1, FPURegister cmp2) {
812 BranchF32(target, nan, cc, cmp1, cmp2, bd);
815 // Alias functions for backward compatibility.
816 inline void BranchF(Label* target, Label* nan, Condition cc, FPURegister cmp1,
817 FPURegister cmp2, BranchDelaySlot bd = PROTECT) {
818 BranchF64(target, nan, cc, cmp1, cmp2, bd);
821 inline void BranchF(BranchDelaySlot bd, Label* target, Label* nan,
822 Condition cc, FPURegister cmp1, FPURegister cmp2) {
823 BranchF64(bd, target, nan, cc, cmp1, cmp2);
826 // Truncates a double using a specific rounding mode, and writes the value
827 // to the result register.
828 // The except_flag will contain any exceptions caused by the instruction.
829 // If check_inexact is kDontCheckForInexactConversion, then the inexact
830 // exception is masked.
831 void EmitFPUTruncate(FPURoundingMode rounding_mode,
833 DoubleRegister double_input,
835 DoubleRegister double_scratch,
836 Register except_flag,
837 CheckForInexactConversion check_inexact
838 = kDontCheckForInexactConversion);
840 // Performs a truncating conversion of a floating point number as used by
841 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. Goes to 'done' if it
842 // succeeds, otherwise falls through if result is saturated. On return
843 // 'result' either holds answer, or is clobbered on fall through.
845 // Only public for the test code in test-code-stubs-arm.cc.
846 void TryInlineTruncateDoubleToI(Register result,
847 DoubleRegister input,
850 // Performs a truncating conversion of a floating point number as used by
851 // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
852 // Exits with 'result' holding the answer.
853 void TruncateDoubleToI(Register result, DoubleRegister double_input);
855 // Performs a truncating conversion of a heap number as used by
856 // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input'
857 // must be different registers. Exits with 'result' holding the answer.
858 void TruncateHeapNumberToI(Register result, Register object);
860 // Converts the smi or heap number in object to an int32 using the rules
861 // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
862 // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be
863 // different registers.
864 void TruncateNumberToI(Register object,
866 Register heap_number_map,
870 // Loads the number from object into dst register.
871 // If |object| is neither smi nor heap number, |not_number| is jumped to
872 // with |object| still intact.
873 void LoadNumber(Register object,
875 Register heap_number_map,
879 // Loads the number from object into double_dst in the double format.
880 // Control will jump to not_int32 if the value cannot be exactly represented
881 // by a 32-bit integer.
882 // Floating point value in the 32-bit integer range that are not exact integer
884 void LoadNumberAsInt32Double(Register object,
885 DoubleRegister double_dst,
886 Register heap_number_map,
889 FPURegister double_scratch,
892 // Loads the number from object into dst as a 32-bit integer.
893 // Control will jump to not_int32 if the object cannot be exactly represented
894 // by a 32-bit integer.
895 // Floating point value in the 32-bit integer range that are not exact integer
896 // won't be converted.
897 void LoadNumberAsInt32(Register object,
899 Register heap_number_map,
902 FPURegister double_scratch0,
903 FPURegister double_scratch1,
907 // argc - argument count to be dropped by LeaveExitFrame.
908 // save_doubles - saves FPU registers on stack, currently disabled.
909 // stack_space - extra stack space.
910 void EnterExitFrame(bool save_doubles,
911 int stack_space = 0);
913 // Leave the current exit frame.
914 void LeaveExitFrame(bool save_doubles, Register arg_count,
915 bool restore_context, bool do_return = NO_EMIT_RETURN,
916 bool argument_count_is_length = false);
918 // Get the actual activation frame alignment for target environment.
919 static int ActivationFrameAlignment();
921 // Make sure the stack is aligned. Only emits code in debug mode.
922 void AssertStackIsAligned();
924 void LoadContext(Register dst, int context_chain_length);
926 // Conditionally load the cached Array transitioned map of type
927 // transitioned_kind from the native context if the map in register
928 // map_in_out is the cached Array map in the native context of
930 void LoadTransitionedArrayMapConditional(
931 ElementsKind expected_kind,
932 ElementsKind transitioned_kind,
935 Label* no_map_match);
937 void LoadGlobalFunction(int index, Register function);
939 // Load the initial map from the global function. The registers
940 // function and map can be the same, function is then overwritten.
941 void LoadGlobalFunctionInitialMap(Register function,
945 void InitializeRootRegister() {
946 ExternalReference roots_array_start =
947 ExternalReference::roots_array_start(isolate());
948 li(kRootRegister, Operand(roots_array_start));
951 // -------------------------------------------------------------------------
952 // JavaScript invokes.
954 // Invoke the JavaScript function code by either calling or jumping.
955 void InvokeCode(Register code,
956 const ParameterCount& expected,
957 const ParameterCount& actual,
959 const CallWrapper& call_wrapper);
961 // Invoke the JavaScript function in the given register. Changes the
962 // current context to the context in the function before invoking.
963 void InvokeFunction(Register function,
964 const ParameterCount& actual,
966 const CallWrapper& call_wrapper);
968 void InvokeFunction(Register function,
969 const ParameterCount& expected,
970 const ParameterCount& actual,
972 const CallWrapper& call_wrapper);
974 void InvokeFunction(Handle<JSFunction> function,
975 const ParameterCount& expected,
976 const ParameterCount& actual,
978 const CallWrapper& call_wrapper);
981 void IsObjectJSObjectType(Register heap_object,
986 void IsInstanceJSObjectType(Register map,
990 void IsObjectJSStringType(Register object,
994 void IsObjectNameType(Register object,
998 // -------------------------------------------------------------------------
1003 // -------------------------------------------------------------------------
1004 // Exception handling.
1006 // Push a new stack handler and link into stack handler chain.
1007 void PushStackHandler();
1009 // Unlink the stack handler on top of the stack from the stack handler chain.
1010 // Must preserve the result register.
1011 void PopStackHandler();
1013 // Copies a fixed number of fields of heap objects from src to dst.
1014 void CopyFields(Register dst, Register src, RegList temps, int field_count);
1016 // Copies a number of bytes from src to dst. All registers are clobbered. On
1017 // exit src and dst will point to the place just after where the last byte was
1018 // read or written and length will be zero.
1019 void CopyBytes(Register src,
1024 // Initialize fields with filler values. Fields starting at |start_offset|
1025 // not including end_offset are overwritten with the value in |filler|. At
1026 // the end the loop, |start_offset| takes the value of |end_offset|.
1027 void InitializeFieldsWithFiller(Register start_offset,
1028 Register end_offset,
1031 // -------------------------------------------------------------------------
1032 // Support functions.
1034 // Machine code version of Map::GetConstructor().
1035 // |temp| holds |result|'s map when done, and |temp2| its instance type.
1036 void GetMapConstructor(Register result, Register map, Register temp,
1039 // Try to get function prototype of a function and puts the value in
1040 // the result register. Checks that the function really is a
1041 // function and jumps to the miss label if the fast checks fail. The
1042 // function register will be untouched; the other registers may be
1044 void TryGetFunctionPrototype(Register function,
1048 bool miss_on_bound_function = false);
1050 void GetObjectType(Register function,
1054 // Check if a map for a JSObject indicates that the object has fast elements.
1055 // Jump to the specified label if it does not.
1056 void CheckFastElements(Register map,
1060 // Check if a map for a JSObject indicates that the object can have both smi
1061 // and HeapObject elements. Jump to the specified label if it does not.
1062 void CheckFastObjectElements(Register map,
1066 // Check if a map for a JSObject indicates that the object has fast smi only
1067 // elements. Jump to the specified label if it does not.
1068 void CheckFastSmiElements(Register map,
1072 // Check to see if maybe_number can be stored as a double in
1073 // FastDoubleElements. If it can, store it at the index specified by key in
1074 // the FastDoubleElements array elements. Otherwise jump to fail.
1075 void StoreNumberToDoubleElements(Register value_reg,
1077 Register elements_reg,
1082 int elements_offset = 0);
1084 // Compare an object's map with the specified map and its transitioned
1085 // elements maps if mode is ALLOW_ELEMENT_TRANSITION_MAPS. Jumps to
1086 // "branch_to" if the result of the comparison is "cond". If multiple map
1087 // compares are required, the compare sequences branches to early_success.
1088 void CompareMapAndBranch(Register obj,
1091 Label* early_success,
1095 // As above, but the map of the object is already loaded into the register
1096 // which is preserved by the code generated.
1097 void CompareMapAndBranch(Register obj_map,
1099 Label* early_success,
1103 // Check if the map of an object is equal to a specified map and branch to
1104 // label if not. Skip the smi check if not required (object is known to be a
1105 // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
1106 // against maps that are ElementsKind transition maps of the specificed map.
1107 void CheckMap(Register obj,
1111 SmiCheckType smi_check_type);
1114 void CheckMap(Register obj,
1116 Heap::RootListIndex index,
1118 SmiCheckType smi_check_type);
1120 // Check if the map of an object is equal to a specified weak map and branch
1121 // to a specified target if equal. Skip the smi check if not required
1122 // (object is known to be a heap object)
1123 void DispatchWeakMap(Register obj, Register scratch1, Register scratch2,
1124 Handle<WeakCell> cell, Handle<Code> success,
1125 SmiCheckType smi_check_type);
1127 // Get value of the weak cell.
1128 void GetWeakValue(Register value, Handle<WeakCell> cell);
1130 // Load the value of the weak cell in the value register. Branch to the
1131 // given miss label is the weak cell was cleared.
1132 void LoadWeakValue(Register value, Handle<WeakCell> cell, Label* miss);
1134 // Load and check the instance type of an object for being a string.
1135 // Loads the type into the second argument register.
1136 // Returns a condition that will be enabled if the object was a string.
1137 Condition IsObjectStringType(Register obj,
1140 lw(type, FieldMemOperand(obj, HeapObject::kMapOffset));
1141 lbu(type, FieldMemOperand(type, Map::kInstanceTypeOffset));
1142 And(type, type, Operand(kIsNotStringMask));
1143 DCHECK_EQ(0u, kStringTag);
1148 // Picks out an array index from the hash field.
1150 // hash - holds the index's hash. Clobbered.
1151 // index - holds the overwritten index on exit.
1152 void IndexFromHash(Register hash, Register index);
1154 // Get the number of least significant bits from a register.
1155 void GetLeastBitsFromSmi(Register dst, Register src, int num_least_bits);
1156 void GetLeastBitsFromInt32(Register dst, Register src, int mun_least_bits);
1158 // Load the value of a number object into a FPU double register. If the
1159 // object is not a number a jump to the label not_number is performed
1160 // and the FPU double register is unchanged.
1161 void ObjectToDoubleFPURegister(
1166 Register heap_number_map,
1168 ObjectToDoubleFlags flags = NO_OBJECT_TO_DOUBLE_FLAGS);
1170 // Load the value of a smi object into a FPU double register. The register
1171 // scratch1 can be the same register as smi in which case smi will hold the
1172 // untagged value afterwards.
1173 void SmiToDoubleFPURegister(Register smi,
1177 // -------------------------------------------------------------------------
1178 // Overflow handling functions.
1179 // Usage: first call the appropriate arithmetic function, then call one of the
1180 // jump functions with the overflow_dst register as the second parameter.
1182 void AdduAndCheckForOverflow(Register dst,
1185 Register overflow_dst,
1186 Register scratch = at);
1188 void AdduAndCheckForOverflow(Register dst, Register left,
1189 const Operand& right, Register overflow_dst,
1190 Register scratch = at);
1192 void SubuAndCheckForOverflow(Register dst,
1195 Register overflow_dst,
1196 Register scratch = at);
1198 void SubuAndCheckForOverflow(Register dst, Register left,
1199 const Operand& right, Register overflow_dst,
1200 Register scratch = at);
1202 void BranchOnOverflow(Label* label,
1203 Register overflow_check,
1204 BranchDelaySlot bd = PROTECT) {
1205 Branch(label, lt, overflow_check, Operand(zero_reg), bd);
1208 void BranchOnNoOverflow(Label* label,
1209 Register overflow_check,
1210 BranchDelaySlot bd = PROTECT) {
1211 Branch(label, ge, overflow_check, Operand(zero_reg), bd);
1214 void RetOnOverflow(Register overflow_check, BranchDelaySlot bd = PROTECT) {
1215 Ret(lt, overflow_check, Operand(zero_reg), bd);
1218 void RetOnNoOverflow(Register overflow_check, BranchDelaySlot bd = PROTECT) {
1219 Ret(ge, overflow_check, Operand(zero_reg), bd);
1222 // -------------------------------------------------------------------------
1225 // See comments at the beginning of CEntryStub::Generate.
1226 inline void PrepareCEntryArgs(int num_args) { li(a0, num_args); }
1228 inline void PrepareCEntryFunction(const ExternalReference& ref) {
1229 li(a1, Operand(ref));
1232 #define COND_ARGS Condition cond = al, Register rs = zero_reg, \
1233 const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
1235 // Call a code stub.
1236 void CallStub(CodeStub* stub,
1237 TypeFeedbackId ast_id = TypeFeedbackId::None(),
1240 // Tail call a code stub (jump).
1241 void TailCallStub(CodeStub* stub, COND_ARGS);
1245 void CallJSExitStub(CodeStub* stub);
1247 // Call a runtime routine.
1248 void CallRuntime(const Runtime::Function* f, int num_arguments,
1249 SaveFPRegsMode save_doubles = kDontSaveFPRegs,
1250 BranchDelaySlot bd = PROTECT);
1251 void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
1252 const Runtime::Function* function = Runtime::FunctionForId(id);
1253 CallRuntime(function, function->nargs, kSaveFPRegs);
1256 // Convenience function: Same as above, but takes the fid instead.
1257 void CallRuntime(Runtime::FunctionId id, int num_arguments,
1258 SaveFPRegsMode save_doubles = kDontSaveFPRegs,
1259 BranchDelaySlot bd = PROTECT) {
1260 CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles, bd);
1263 // Convenience function: call an external reference.
1264 void CallExternalReference(const ExternalReference& ext,
1266 BranchDelaySlot bd = PROTECT);
1268 // Tail call of a runtime routine (jump).
1269 // Like JumpToExternalReference, but also takes care of passing the number
1271 void TailCallExternalReference(const ExternalReference& ext,
1275 // Convenience function: tail call a runtime routine (jump).
1276 void TailCallRuntime(Runtime::FunctionId fid,
1280 int CalculateStackPassedWords(int num_reg_arguments,
1281 int num_double_arguments);
1283 // Before calling a C-function from generated code, align arguments on stack
1284 // and add space for the four mips argument slots.
1285 // After aligning the frame, non-register arguments must be stored on the
1286 // stack, after the argument-slots using helper: CFunctionArgumentOperand().
1287 // The argument count assumes all arguments are word sized.
1288 // Some compilers/platforms require the stack to be aligned when calling
1290 // Needs a scratch register to do some arithmetic. This register will be
1292 void PrepareCallCFunction(int num_reg_arguments,
1293 int num_double_registers,
1295 void PrepareCallCFunction(int num_reg_arguments,
1298 // Arguments 1-4 are placed in registers a0 thru a3 respectively.
1299 // Arguments 5..n are stored to stack using following:
1300 // sw(t0, CFunctionArgumentOperand(5));
1302 // Calls a C function and cleans up the space for arguments allocated
1303 // by PrepareCallCFunction. The called function is not allowed to trigger a
1304 // garbage collection, since that might move the code and invalidate the
1305 // return address (unless this is somehow accounted for by the called
1307 void CallCFunction(ExternalReference function, int num_arguments);
1308 void CallCFunction(Register function, int num_arguments);
1309 void CallCFunction(ExternalReference function,
1310 int num_reg_arguments,
1311 int num_double_arguments);
1312 void CallCFunction(Register function,
1313 int num_reg_arguments,
1314 int num_double_arguments);
1315 void MovFromFloatResult(DoubleRegister dst);
1316 void MovFromFloatParameter(DoubleRegister dst);
1318 // There are two ways of passing double arguments on MIPS, depending on
1319 // whether soft or hard floating point ABI is used. These functions
1320 // abstract parameter passing for the three different ways we call
1321 // C functions from generated code.
1322 void MovToFloatParameter(DoubleRegister src);
1323 void MovToFloatParameters(DoubleRegister src1, DoubleRegister src2);
1324 void MovToFloatResult(DoubleRegister src);
1326 // Jump to the builtin routine.
1327 void JumpToExternalReference(const ExternalReference& builtin,
1328 BranchDelaySlot bd = PROTECT);
1330 // Invoke specified builtin JavaScript function. Adds an entry to
1331 // the unresolved list if the name does not resolve.
1332 void InvokeBuiltin(Builtins::JavaScript id,
1334 const CallWrapper& call_wrapper = NullCallWrapper());
1336 // Store the code object for the given builtin in the target register and
1337 // setup the function in a1.
1338 void GetBuiltinEntry(Register target, Builtins::JavaScript id);
1340 // Store the function for the given builtin in the target register.
1341 void GetBuiltinFunction(Register target, Builtins::JavaScript id);
1345 uint32_t flags; // See Bootstrapper::FixupFlags decoders/encoders.
1349 Handle<Object> CodeObject() {
1350 DCHECK(!code_object_.is_null());
1351 return code_object_;
1354 // Emit code for a truncating division by a constant. The dividend register is
1355 // unchanged and at gets clobbered. Dividend and result must be different.
1356 void TruncatingDiv(Register result, Register dividend, int32_t divisor);
1358 // -------------------------------------------------------------------------
1359 // StatsCounter support.
1361 void SetCounter(StatsCounter* counter, int value,
1362 Register scratch1, Register scratch2);
1363 void IncrementCounter(StatsCounter* counter, int value,
1364 Register scratch1, Register scratch2);
1365 void DecrementCounter(StatsCounter* counter, int value,
1366 Register scratch1, Register scratch2);
1369 // -------------------------------------------------------------------------
1372 // Calls Abort(msg) if the condition cc is not satisfied.
1373 // Use --debug_code to enable.
1374 void Assert(Condition cc, BailoutReason reason, Register rs, Operand rt);
1375 void AssertFastElements(Register elements);
1377 // Like Assert(), but always enabled.
1378 void Check(Condition cc, BailoutReason reason, Register rs, Operand rt);
1380 // Print a message to stdout and abort execution.
1381 void Abort(BailoutReason msg);
1383 // Verify restrictions about code generated in stubs.
1384 void set_generating_stub(bool value) { generating_stub_ = value; }
1385 bool generating_stub() { return generating_stub_; }
1386 void set_has_frame(bool value) { has_frame_ = value; }
1387 bool has_frame() { return has_frame_; }
1388 inline bool AllowThisStubCall(CodeStub* stub);
1390 // ---------------------------------------------------------------------------
1391 // Number utilities.
1393 // Check whether the value of reg is a power of two and not zero. If not
1394 // control continues at the label not_power_of_two. If reg is a power of two
1395 // the register scratch contains the value of (reg - 1) when control falls
1397 void JumpIfNotPowerOfTwoOrZero(Register reg,
1399 Label* not_power_of_two_or_zero);
1401 // -------------------------------------------------------------------------
1404 void SmiTag(Register reg) {
1405 Addu(reg, reg, reg);
1408 // Test for overflow < 0: use BranchOnOverflow() or BranchOnNoOverflow().
1409 void SmiTagCheckOverflow(Register reg, Register overflow);
1410 void SmiTagCheckOverflow(Register dst, Register src, Register overflow);
1412 void SmiTag(Register dst, Register src) {
1413 Addu(dst, src, src);
1416 // Try to convert int32 to smi. If the value is to large, preserve
1417 // the original value and jump to not_a_smi. Destroys scratch and
1419 void TrySmiTag(Register reg, Register scratch, Label* not_a_smi) {
1420 TrySmiTag(reg, reg, scratch, not_a_smi);
1422 void TrySmiTag(Register dst,
1426 SmiTagCheckOverflow(at, src, scratch);
1427 BranchOnOverflow(not_a_smi, scratch);
1431 void SmiUntag(Register reg) {
1432 sra(reg, reg, kSmiTagSize);
1435 void SmiUntag(Register dst, Register src) {
1436 sra(dst, src, kSmiTagSize);
1439 // Test if the register contains a smi.
1440 inline void SmiTst(Register value, Register scratch) {
1441 And(scratch, value, Operand(kSmiTagMask));
1443 inline void NonNegativeSmiTst(Register value, Register scratch) {
1444 And(scratch, value, Operand(kSmiTagMask | kSmiSignMask));
1447 // Untag the source value into destination and jump if source is a smi.
1448 // Souce and destination can be the same register.
1449 void UntagAndJumpIfSmi(Register dst, Register src, Label* smi_case);
1451 // Untag the source value into destination and jump if source is not a smi.
1452 // Souce and destination can be the same register.
1453 void UntagAndJumpIfNotSmi(Register dst, Register src, Label* non_smi_case);
1455 // Jump the register contains a smi.
1456 void JumpIfSmi(Register value,
1458 Register scratch = at,
1459 BranchDelaySlot bd = PROTECT);
1461 // Jump if the register contains a non-smi.
1462 void JumpIfNotSmi(Register value,
1463 Label* not_smi_label,
1464 Register scratch = at,
1465 BranchDelaySlot bd = PROTECT);
1467 // Jump if either of the registers contain a non-smi.
1468 void JumpIfNotBothSmi(Register reg1, Register reg2, Label* on_not_both_smi);
1469 // Jump if either of the registers contain a smi.
1470 void JumpIfEitherSmi(Register reg1, Register reg2, Label* on_either_smi);
1472 // Abort execution if argument is a smi, enabled via --debug-code.
1473 void AssertNotSmi(Register object);
1474 void AssertSmi(Register object);
1476 // Abort execution if argument is not a string, enabled via --debug-code.
1477 void AssertString(Register object);
1479 // Abort execution if argument is not a name, enabled via --debug-code.
1480 void AssertName(Register object);
1482 // Abort execution if argument is not undefined or an AllocationSite, enabled
1483 // via --debug-code.
1484 void AssertUndefinedOrAllocationSite(Register object, Register scratch);
1486 // Abort execution if reg is not the root value with the given index,
1487 // enabled via --debug-code.
1488 void AssertIsRoot(Register reg, Heap::RootListIndex index);
1490 // ---------------------------------------------------------------------------
1491 // HeapNumber utilities.
1493 void JumpIfNotHeapNumber(Register object,
1494 Register heap_number_map,
1496 Label* on_not_heap_number);
1498 // -------------------------------------------------------------------------
1499 // String utilities.
1501 // Generate code to do a lookup in the number string cache. If the number in
1502 // the register object is found in the cache the generated code falls through
1503 // with the result in the result register. The object and the result register
1504 // can be the same. If the number is not found in the cache the code jumps to
1505 // the label not_found with only the content of register object unchanged.
1506 void LookupNumberStringCache(Register object,
1513 // Checks if both instance types are sequential ASCII strings and jumps to
1514 // label if either is not.
1515 void JumpIfBothInstanceTypesAreNotSequentialOneByte(
1516 Register first_object_instance_type, Register second_object_instance_type,
1517 Register scratch1, Register scratch2, Label* failure);
1519 // Check if instance type is sequential one-byte string and jump to label if
1521 void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch,
1524 void JumpIfNotUniqueNameInstanceType(Register reg, Label* not_unique_name);
1526 void EmitSeqStringSetCharCheck(Register string,
1530 uint32_t encoding_mask);
1532 // Checks if both objects are sequential one-byte strings and jumps to label
1533 // if either is not. Assumes that neither object is a smi.
1534 void JumpIfNonSmisNotBothSequentialOneByteStrings(Register first,
1540 // Checks if both objects are sequential one-byte strings and jumps to label
1541 // if either is not.
1542 void JumpIfNotBothSequentialOneByteStrings(Register first, Register second,
1545 Label* not_flat_one_byte_strings);
1547 void ClampUint8(Register output_reg, Register input_reg);
1549 void ClampDoubleToUint8(Register result_reg,
1550 DoubleRegister input_reg,
1551 DoubleRegister temp_double_reg);
1554 void LoadInstanceDescriptors(Register map, Register descriptors);
1555 void EnumLength(Register dst, Register map);
1556 void NumberOfOwnDescriptors(Register dst, Register map);
1557 void LoadAccessor(Register dst, Register holder, int accessor_index,
1558 AccessorComponent accessor);
1560 template<typename Field>
1561 void DecodeField(Register dst, Register src) {
1562 Ext(dst, src, Field::kShift, Field::kSize);
1565 template<typename Field>
1566 void DecodeField(Register reg) {
1567 DecodeField<Field>(reg, reg);
1570 template<typename Field>
1571 void DecodeFieldToSmi(Register dst, Register src) {
1572 static const int shift = Field::kShift;
1573 static const int mask = Field::kMask >> shift << kSmiTagSize;
1574 STATIC_ASSERT((mask & (0x80000000u >> (kSmiTagSize - 1))) == 0);
1575 STATIC_ASSERT(kSmiTag == 0);
1576 if (shift < kSmiTagSize) {
1577 sll(dst, src, kSmiTagSize - shift);
1578 And(dst, dst, Operand(mask));
1579 } else if (shift > kSmiTagSize) {
1580 srl(dst, src, shift - kSmiTagSize);
1581 And(dst, dst, Operand(mask));
1583 And(dst, src, Operand(mask));
1587 template<typename Field>
1588 void DecodeFieldToSmi(Register reg) {
1589 DecodeField<Field>(reg, reg);
1592 // Generates function and stub prologue code.
1593 void StubPrologue();
1594 void Prologue(bool code_pre_aging);
1596 // Activation support.
1597 void EnterFrame(StackFrame::Type type);
1598 void EnterFrame(StackFrame::Type type, bool load_constant_pool_pointer_reg);
1599 void LeaveFrame(StackFrame::Type type);
1601 // Patch the relocated value (lui/ori pair).
1602 void PatchRelocatedValue(Register li_location,
1604 Register new_value);
1605 // Get the relocatad value (loaded data) from the lui/ori pair.
1606 void GetRelocatedValue(Register li_location,
1610 // Expects object in a0 and returns map with validated enum cache
1611 // in a0. Assumes that any other register can be used as a scratch.
1612 void CheckEnumCache(Register null_value, Label* call_runtime);
1614 // AllocationMemento support. Arrays may have an associated
1615 // AllocationMemento object that can be checked for in order to pretransition
1617 // On entry, receiver_reg should point to the array object.
1618 // scratch_reg gets clobbered.
1619 // If allocation info is present, jump to allocation_memento_present.
1620 void TestJSArrayForAllocationMemento(
1621 Register receiver_reg,
1622 Register scratch_reg,
1623 Label* no_memento_found,
1624 Condition cond = al,
1625 Label* allocation_memento_present = NULL);
1627 void JumpIfJSArrayHasAllocationMemento(Register receiver_reg,
1628 Register scratch_reg,
1629 Label* memento_found) {
1630 Label no_memento_found;
1631 TestJSArrayForAllocationMemento(receiver_reg, scratch_reg,
1632 &no_memento_found, eq, memento_found);
1633 bind(&no_memento_found);
1636 // Jumps to found label if a prototype map has dictionary elements.
1637 void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
1638 Register scratch1, Label* found);
1641 void CallCFunctionHelper(Register function,
1642 int num_reg_arguments,
1643 int num_double_arguments);
1645 void BranchAndLinkShort(int16_t offset, BranchDelaySlot bdslot = PROTECT);
1646 void BranchAndLinkShort(int16_t offset, Condition cond, Register rs,
1648 BranchDelaySlot bdslot = PROTECT);
1649 void BranchAndLinkShort(Label* L, BranchDelaySlot bdslot = PROTECT);
1650 void BranchAndLinkShort(Label* L, Condition cond, Register rs,
1652 BranchDelaySlot bdslot = PROTECT);
1653 void Jr(Label* L, BranchDelaySlot bdslot);
1654 void Jalr(Label* L, BranchDelaySlot bdslot);
1656 // Common implementation of BranchF functions for the different formats.
1657 void BranchFCommon(SecondaryField sizeField, Label* target, Label* nan,
1658 Condition cc, FPURegister cmp1, FPURegister cmp2,
1659 BranchDelaySlot bd = PROTECT);
1661 void BranchShortF(SecondaryField sizeField, Label* target, Condition cc,
1662 FPURegister cmp1, FPURegister cmp2,
1663 BranchDelaySlot bd = PROTECT);
1665 // Helper functions for generating invokes.
1666 void InvokePrologue(const ParameterCount& expected,
1667 const ParameterCount& actual,
1668 Handle<Code> code_constant,
1671 bool* definitely_mismatches,
1673 const CallWrapper& call_wrapper);
1675 // Get the code for the given builtin. Returns if able to resolve
1676 // the function in the 'resolved' flag.
1677 Handle<Code> ResolveBuiltin(Builtins::JavaScript id, bool* resolved);
1679 void InitializeNewString(Register string,
1681 Heap::RootListIndex map_index,
1685 // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
1686 void InNewSpace(Register object,
1688 Condition cond, // eq for new space, ne otherwise.
1691 // Helper for finding the mark bits for an address. Afterwards, the
1692 // bitmap register points at the word with the mark bits and the mask
1693 // the position of the first bit. Leaves addr_reg unchanged.
1694 inline void GetMarkBits(Register addr_reg,
1695 Register bitmap_reg,
1698 // Compute memory operands for safepoint stack slots.
1699 static int SafepointRegisterStackIndex(int reg_code);
1700 MemOperand SafepointRegisterSlot(Register reg);
1701 MemOperand SafepointRegistersAndDoublesSlot(Register reg);
1703 bool generating_stub_;
1705 bool has_double_zero_reg_set_;
1706 // This handle will be patched with the code object on installation.
1707 Handle<Object> code_object_;
1709 // Needs access to SafepointRegisterStackIndex for compiled frame
1711 friend class StandardFrame;
1715 // The code patcher is used to patch (typically) small parts of code e.g. for
1716 // debugging and other types of instrumentation. When using the code patcher
1717 // the exact number of bytes specified must be emitted. It is not legal to emit
1718 // relocation information. If any of these constraints are violated it causes
1719 // an assertion to fail.
1727 CodePatcher(byte* address,
1729 FlushICache flush_cache = FLUSH);
1732 // Macro assembler to emit code.
1733 MacroAssembler* masm() { return &masm_; }
1735 // Emit an instruction directly.
1736 void Emit(Instr instr);
1738 // Emit an address directly.
1739 void Emit(Address addr);
1741 // Change the condition part of an instruction leaving the rest of the current
1742 // instruction unchanged.
1743 void ChangeBranchCondition(Condition cond);
1746 byte* address_; // The address of the code being patched.
1747 int size_; // Number of bytes of the expected patch size.
1748 MacroAssembler masm_; // Macro assembler used to generate the code.
1749 FlushICache flush_cache_; // Whether to flush the I cache after patching.
1754 #ifdef GENERATED_CODE_COVERAGE
1755 #define CODE_COVERAGE_STRINGIFY(x) #x
1756 #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
1757 #define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
1758 #define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
1760 #define ACCESS_MASM(masm) masm->
1763 } } // namespace v8::internal
1765 #endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_