Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef jit_mips_Assembler_mips_h
8 #define jit_mips_Assembler_mips_h
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/MathAlgorithms.h"
14 #include "jit/CompactBuffer.h"
15 #include "jit/IonCode.h"
16 #include "jit/IonSpewer.h"
17 #include "jit/mips/Architecture-mips.h"
18 #include "jit/shared/Assembler-shared.h"
19 #include "jit/shared/IonAssemblerBuffer.h"
21 namespace js {
22 namespace jit {
24 static MOZ_CONSTEXPR_VAR Register zero = { Registers::zero };
25 static MOZ_CONSTEXPR_VAR Register at = { Registers::at };
26 static MOZ_CONSTEXPR_VAR Register v0 = { Registers::v0 };
27 static MOZ_CONSTEXPR_VAR Register v1 = { Registers::v1 };
28 static MOZ_CONSTEXPR_VAR Register a0 = { Registers::a0 };
29 static MOZ_CONSTEXPR_VAR Register a1 = { Registers::a1 };
30 static MOZ_CONSTEXPR_VAR Register a2 = { Registers::a2 };
31 static MOZ_CONSTEXPR_VAR Register a3 = { Registers::a3 };
32 static MOZ_CONSTEXPR_VAR Register t0 = { Registers::t0 };
33 static MOZ_CONSTEXPR_VAR Register t1 = { Registers::t1 };
34 static MOZ_CONSTEXPR_VAR Register t2 = { Registers::t2 };
35 static MOZ_CONSTEXPR_VAR Register t3 = { Registers::t3 };
36 static MOZ_CONSTEXPR_VAR Register t4 = { Registers::t4 };
37 static MOZ_CONSTEXPR_VAR Register t5 = { Registers::t5 };
38 static MOZ_CONSTEXPR_VAR Register t6 = { Registers::t6 };
39 static MOZ_CONSTEXPR_VAR Register t7 = { Registers::t7 };
40 static MOZ_CONSTEXPR_VAR Register s0 = { Registers::s0 };
41 static MOZ_CONSTEXPR_VAR Register s1 = { Registers::s1 };
42 static MOZ_CONSTEXPR_VAR Register s2 = { Registers::s2 };
43 static MOZ_CONSTEXPR_VAR Register s3 = { Registers::s3 };
44 static MOZ_CONSTEXPR_VAR Register s4 = { Registers::s4 };
45 static MOZ_CONSTEXPR_VAR Register s5 = { Registers::s5 };
46 static MOZ_CONSTEXPR_VAR Register s6 = { Registers::s6 };
47 static MOZ_CONSTEXPR_VAR Register s7 = { Registers::s7 };
48 static MOZ_CONSTEXPR_VAR Register t8 = { Registers::t8 };
49 static MOZ_CONSTEXPR_VAR Register t9 = { Registers::t9 };
50 static MOZ_CONSTEXPR_VAR Register k0 = { Registers::k0 };
51 static MOZ_CONSTEXPR_VAR Register k1 = { Registers::k1 };
52 static MOZ_CONSTEXPR_VAR Register gp = { Registers::gp };
53 static MOZ_CONSTEXPR_VAR Register sp = { Registers::sp };
54 static MOZ_CONSTEXPR_VAR Register fp = { Registers::fp };
55 static MOZ_CONSTEXPR_VAR Register ra = { Registers::ra };
57 static MOZ_CONSTEXPR_VAR Register ScratchRegister = at;
58 static MOZ_CONSTEXPR_VAR Register SecondScratchReg = t8;
60 // Use arg reg from EnterJIT function as OsrFrameReg.
61 static MOZ_CONSTEXPR_VAR Register OsrFrameReg = a3;
62 static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = s3;
63 static MOZ_CONSTEXPR_VAR Register CallTempReg0 = t0;
64 static MOZ_CONSTEXPR_VAR Register CallTempReg1 = t1;
65 static MOZ_CONSTEXPR_VAR Register CallTempReg2 = t2;
66 static MOZ_CONSTEXPR_VAR Register CallTempReg3 = t3;
67 static MOZ_CONSTEXPR_VAR Register CallTempReg4 = t4;
68 static MOZ_CONSTEXPR_VAR Register CallTempReg5 = t5;
70 static MOZ_CONSTEXPR_VAR Register IntArgReg0 = a0;
71 static MOZ_CONSTEXPR_VAR Register IntArgReg1 = a1;
72 static MOZ_CONSTEXPR_VAR Register IntArgReg2 = a2;
73 static MOZ_CONSTEXPR_VAR Register IntArgReg3 = a3;
74 static MOZ_CONSTEXPR_VAR Register GlobalReg = s6; // used by Odin
75 static MOZ_CONSTEXPR_VAR Register HeapReg = s7; // used by Odin
76 static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { t0, t1, t2, t3, t4 };
77 static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs);
79 class ABIArgGenerator
80 {
81 unsigned usedArgSlots_;
82 bool firstArgFloat;
83 ABIArg current_;
85 public:
86 ABIArgGenerator();
87 ABIArg next(MIRType argType);
88 ABIArg ¤t() { return current_; }
90 uint32_t stackBytesConsumedSoFar() const {
91 if (usedArgSlots_ <= 4)
92 return 4 * sizeof(intptr_t);
94 return usedArgSlots_ * sizeof(intptr_t);
95 }
97 static const Register NonArgReturnVolatileReg0;
98 static const Register NonArgReturnVolatileReg1;
99 };
101 static MOZ_CONSTEXPR_VAR Register PreBarrierReg = a1;
103 static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
104 static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg };
106 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = v1;
107 static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = v0;
108 static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
109 static MOZ_CONSTEXPR_VAR Register FramePointer = fp;
110 static MOZ_CONSTEXPR_VAR Register ReturnReg = v0;
111 static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::f0 };
112 static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::f18 };
113 static MOZ_CONSTEXPR_VAR FloatRegister SecondScratchFloatReg = { FloatRegisters::f16 };
115 static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::f30 };
117 static MOZ_CONSTEXPR_VAR FloatRegister f0 = {FloatRegisters::f0};
118 static MOZ_CONSTEXPR_VAR FloatRegister f2 = {FloatRegisters::f2};
119 static MOZ_CONSTEXPR_VAR FloatRegister f4 = {FloatRegisters::f4};
120 static MOZ_CONSTEXPR_VAR FloatRegister f6 = {FloatRegisters::f6};
121 static MOZ_CONSTEXPR_VAR FloatRegister f8 = {FloatRegisters::f8};
122 static MOZ_CONSTEXPR_VAR FloatRegister f10 = {FloatRegisters::f10};
123 static MOZ_CONSTEXPR_VAR FloatRegister f12 = {FloatRegisters::f12};
124 static MOZ_CONSTEXPR_VAR FloatRegister f14 = {FloatRegisters::f14};
125 static MOZ_CONSTEXPR_VAR FloatRegister f16 = {FloatRegisters::f16};
126 static MOZ_CONSTEXPR_VAR FloatRegister f18 = {FloatRegisters::f18};
127 static MOZ_CONSTEXPR_VAR FloatRegister f20 = {FloatRegisters::f20};
128 static MOZ_CONSTEXPR_VAR FloatRegister f22 = {FloatRegisters::f22};
129 static MOZ_CONSTEXPR_VAR FloatRegister f24 = {FloatRegisters::f24};
130 static MOZ_CONSTEXPR_VAR FloatRegister f26 = {FloatRegisters::f26};
131 static MOZ_CONSTEXPR_VAR FloatRegister f28 = {FloatRegisters::f28};
132 static MOZ_CONSTEXPR_VAR FloatRegister f30 = {FloatRegisters::f30};
134 // MIPS CPUs can only load multibyte data that is "naturally"
135 // four-byte-aligned, sp register should be eight-byte-aligned.
136 static const uint32_t StackAlignment = 8;
137 static const uint32_t CodeAlignment = 4;
138 static const bool StackKeptAligned = true;
139 // NativeFrameSize is the size of return adress on stack in AsmJS functions.
140 static const uint32_t NativeFrameSize = sizeof(void*);
141 static const uint32_t AlignmentAtPrologue = 0;
142 static const uint32_t AlignmentMidPrologue = NativeFrameSize;
144 static const Scale ScalePointer = TimesFour;
146 // MIPS instruction types
147 // +---------------------------------------------------------------+
148 // | 6 | 5 | 5 | 5 | 5 | 6 |
149 // +---------------------------------------------------------------+
150 // Register type | Opcode | Rs | Rt | Rd | Sa | Function |
151 // +---------------------------------------------------------------+
152 // | 6 | 5 | 5 | 16 |
153 // +---------------------------------------------------------------+
154 // Immediate type | Opcode | Rs | Rt | 2's complement constant |
155 // +---------------------------------------------------------------+
156 // | 6 | 26 |
157 // +---------------------------------------------------------------+
158 // Jump type | Opcode | jump_target |
159 // +---------------------------------------------------------------+
160 // 31 bit bit 0
162 // MIPS instruction encoding constants.
163 static const uint32_t OpcodeShift = 26;
164 static const uint32_t OpcodeBits = 6;
165 static const uint32_t RSShift = 21;
166 static const uint32_t RSBits = 5;
167 static const uint32_t RTShift = 16;
168 static const uint32_t RTBits = 5;
169 static const uint32_t RDShift = 11;
170 static const uint32_t RDBits = 5;
171 static const uint32_t SAShift = 6;
172 static const uint32_t SABits = 5;
173 static const uint32_t FunctionShift = 0;
174 static const uint32_t FunctionBits = 5;
175 static const uint32_t Imm16Shift = 0;
176 static const uint32_t Imm16Bits = 16;
177 static const uint32_t Imm26Shift = 0;
178 static const uint32_t Imm26Bits = 26;
179 static const uint32_t Imm28Shift = 0;
180 static const uint32_t Imm28Bits = 28;
181 static const uint32_t ImmFieldShift = 2;
182 static const uint32_t FccMask = 0x7;
183 static const uint32_t FccShift = 2;
186 // MIPS instruction field bit masks.
187 static const uint32_t OpcodeMask = ((1 << OpcodeBits) - 1) << OpcodeShift;
188 static const uint32_t Imm16Mask = ((1 << Imm16Bits) - 1) << Imm16Shift;
189 static const uint32_t Imm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift;
190 static const uint32_t Imm28Mask = ((1 << Imm28Bits) - 1) << Imm28Shift;
191 static const uint32_t RSMask = ((1 << RSBits) - 1) << RSShift;
192 static const uint32_t RTMask = ((1 << RTBits) - 1) << RTShift;
193 static const uint32_t RDMask = ((1 << RDBits) - 1) << RDShift;
194 static const uint32_t SAMask = ((1 << SABits) - 1) << SAShift;
195 static const uint32_t FunctionMask = ((1 << FunctionBits) - 1) << FunctionShift;
196 static const uint32_t RegMask = Registers::Total - 1;
197 static const uint32_t StackAlignmentMask = StackAlignment - 1;
199 static const int32_t MAX_BREAK_CODE = 1024 - 1;
201 class Instruction;
202 class InstReg;
203 class InstImm;
204 class InstJump;
205 class BranchInstBlock;
207 uint32_t RS(Register r);
208 uint32_t RT(Register r);
209 uint32_t RT(uint32_t regCode);
210 uint32_t RT(FloatRegister r);
211 uint32_t RD(Register r);
212 uint32_t RD(FloatRegister r);
213 uint32_t RD(uint32_t regCode);
214 uint32_t SA(uint32_t value);
215 uint32_t SA(FloatRegister r);
217 Register toRS (Instruction &i);
218 Register toRT (Instruction &i);
219 Register toRD (Instruction &i);
220 Register toR (Instruction &i);
222 // MIPS enums for instruction fields
223 enum Opcode {
224 op_special = 0 << OpcodeShift,
225 op_regimm = 1 << OpcodeShift,
227 op_j = 2 << OpcodeShift,
228 op_jal = 3 << OpcodeShift,
229 op_beq = 4 << OpcodeShift,
230 op_bne = 5 << OpcodeShift,
231 op_blez = 6 << OpcodeShift,
232 op_bgtz = 7 << OpcodeShift,
234 op_addi = 8 << OpcodeShift,
235 op_addiu = 9 << OpcodeShift,
236 op_slti = 10 << OpcodeShift,
237 op_sltiu = 11 << OpcodeShift,
238 op_andi = 12 << OpcodeShift,
239 op_ori = 13 << OpcodeShift,
240 op_xori = 14 << OpcodeShift,
241 op_lui = 15 << OpcodeShift,
243 op_cop1 = 17 << OpcodeShift,
244 op_cop1x = 19 << OpcodeShift,
246 op_beql = 20 << OpcodeShift,
247 op_bnel = 21 << OpcodeShift,
248 op_blezl = 22 << OpcodeShift,
249 op_bgtzl = 23 << OpcodeShift,
251 op_special2 = 28 << OpcodeShift,
252 op_special3 = 31 << OpcodeShift,
254 op_lb = 32 << OpcodeShift,
255 op_lh = 33 << OpcodeShift,
256 op_lwl = 34 << OpcodeShift,
257 op_lw = 35 << OpcodeShift,
258 op_lbu = 36 << OpcodeShift,
259 op_lhu = 37 << OpcodeShift,
260 op_lwr = 38 << OpcodeShift,
261 op_sb = 40 << OpcodeShift,
262 op_sh = 41 << OpcodeShift,
263 op_swl = 42 << OpcodeShift,
264 op_sw = 43 << OpcodeShift,
265 op_swr = 46 << OpcodeShift,
267 op_lwc1 = 49 << OpcodeShift,
268 op_ldc1 = 53 << OpcodeShift,
270 op_swc1 = 57 << OpcodeShift,
271 op_sdc1 = 61 << OpcodeShift
272 };
274 enum RSField {
275 rs_zero = 0 << RSShift,
276 // cop1 encoding of RS field.
277 rs_mfc1 = 0 << RSShift,
278 rs_one = 1 << RSShift,
279 rs_cfc1 = 2 << RSShift,
280 rs_mfhc1 = 3 << RSShift,
281 rs_mtc1 = 4 << RSShift,
282 rs_ctc1 = 6 << RSShift,
283 rs_mthc1 = 7 << RSShift,
284 rs_bc1 = 8 << RSShift,
285 rs_s = 16 << RSShift,
286 rs_d = 17 << RSShift,
287 rs_w = 20 << RSShift,
288 rs_ps = 22 << RSShift
289 };
291 enum RTField {
292 rt_zero = 0 << RTShift,
293 // regimm encoding of RT field.
294 rt_bltz = 0 << RTShift,
295 rt_bgez = 1 << RTShift,
296 rt_bltzal = 16 << RTShift,
297 rt_bgezal = 17 << RTShift
298 };
300 enum FunctionField {
301 // special encoding of function field.
302 ff_sll = 0,
303 ff_movci = 1,
304 ff_srl = 2,
305 ff_sra = 3,
306 ff_sllv = 4,
307 ff_srlv = 6,
308 ff_srav = 7,
310 ff_jr = 8,
311 ff_jalr = 9,
312 ff_movz = 10,
313 ff_movn = 11,
314 ff_break = 13,
316 ff_mfhi = 16,
317 ff_mflo = 18,
319 ff_mult = 24,
320 ff_multu = 25,
321 ff_div = 26,
322 ff_divu = 27,
324 ff_add = 32,
325 ff_addu = 33,
326 ff_sub = 34,
327 ff_subu = 35,
328 ff_and = 36,
329 ff_or = 37,
330 ff_xor = 38,
331 ff_nor = 39,
333 ff_slt = 42,
334 ff_sltu = 43,
336 // special2 encoding of function field.
337 ff_mul = 2,
338 ff_clz = 32,
339 ff_clo = 33,
341 // special3 encoding of function field.
342 ff_ext = 0,
343 ff_ins = 4,
345 // cop1 encoding of function field.
346 ff_add_fmt = 0,
347 ff_sub_fmt = 1,
348 ff_mul_fmt = 2,
349 ff_div_fmt = 3,
350 ff_sqrt_fmt = 4,
351 ff_abs_fmt = 5,
352 ff_mov_fmt = 6,
353 ff_neg_fmt = 7,
355 ff_round_w_fmt = 12,
356 ff_trunc_w_fmt = 13,
357 ff_ceil_w_fmt = 14,
358 ff_floor_w_fmt = 15,
360 ff_cvt_s_fmt = 32,
361 ff_cvt_d_fmt = 33,
362 ff_cvt_w_fmt = 36,
364 ff_c_f_fmt = 48,
365 ff_c_un_fmt = 49,
366 ff_c_eq_fmt = 50,
367 ff_c_ueq_fmt = 51,
368 ff_c_olt_fmt = 52,
369 ff_c_ult_fmt = 53,
370 ff_c_ole_fmt = 54,
371 ff_c_ule_fmt = 55,
372 };
374 class MacroAssemblerMIPS;
375 class Operand;
377 // A BOffImm16 is a 16 bit immediate that is used for branches.
378 class BOffImm16
379 {
380 uint32_t data;
382 public:
383 uint32_t encode() {
384 JS_ASSERT(!isInvalid());
385 return data;
386 }
387 int32_t decode() {
388 JS_ASSERT(!isInvalid());
389 return (int32_t(data << 18) >> 16) + 4;
390 }
392 explicit BOffImm16(int offset)
393 : data ((offset - 4) >> 2 & Imm16Mask)
394 {
395 JS_ASSERT((offset & 0x3) == 0);
396 JS_ASSERT(isInRange(offset));
397 }
398 static bool isInRange(int offset) {
399 if ((offset - 4) < (INT16_MIN << 2))
400 return false;
401 if ((offset - 4) > (INT16_MAX << 2))
402 return false;
403 return true;
404 }
405 static const uint32_t INVALID = 0x00020000;
406 BOffImm16()
407 : data(INVALID)
408 { }
410 bool isInvalid() {
411 return data == INVALID;
412 }
413 Instruction *getDest(Instruction *src);
415 BOffImm16(InstImm inst);
416 };
418 // A JOffImm26 is a 26 bit immediate that is used for unconditional jumps.
419 class JOffImm26
420 {
421 uint32_t data;
423 public:
424 uint32_t encode() {
425 JS_ASSERT(!isInvalid());
426 return data;
427 }
428 int32_t decode() {
429 JS_ASSERT(!isInvalid());
430 return (int32_t(data << 8) >> 6) + 4;
431 }
433 explicit JOffImm26(int offset)
434 : data ((offset - 4) >> 2 & Imm26Mask)
435 {
436 JS_ASSERT((offset & 0x3) == 0);
437 JS_ASSERT(isInRange(offset));
438 }
439 static bool isInRange(int offset) {
440 if ((offset - 4) < -536870912)
441 return false;
442 if ((offset - 4) > 536870908)
443 return false;
444 return true;
445 }
446 static const uint32_t INVALID = 0x20000000;
447 JOffImm26()
448 : data(INVALID)
449 { }
451 bool isInvalid() {
452 return data == INVALID;
453 }
454 Instruction *getDest(Instruction *src);
456 };
458 class Imm16
459 {
460 uint16_t value;
462 public:
463 Imm16();
464 Imm16(uint32_t imm)
465 : value(imm)
466 { }
467 uint32_t encode() {
468 return value;
469 }
470 int32_t decodeSigned() {
471 return value;
472 }
473 uint32_t decodeUnsigned() {
474 return value;
475 }
476 static bool isInSignedRange(int32_t imm) {
477 return imm >= INT16_MIN && imm <= INT16_MAX;
478 }
479 static bool isInUnsignedRange(uint32_t imm) {
480 return imm <= UINT16_MAX ;
481 }
482 static Imm16 lower (Imm32 imm) {
483 return Imm16(imm.value & 0xffff);
484 }
485 static Imm16 upper (Imm32 imm) {
486 return Imm16((imm.value >> 16) & 0xffff);
487 }
488 };
490 class Operand
491 {
492 public:
493 enum Tag {
494 REG,
495 FREG,
496 MEM
497 };
499 private:
500 Tag tag : 3;
501 uint32_t reg : 5;
502 int32_t offset;
504 public:
505 Operand (Register reg_)
506 : tag(REG), reg(reg_.code())
507 { }
509 Operand (FloatRegister freg)
510 : tag(FREG), reg(freg.code())
511 { }
513 Operand (Register base, Imm32 off)
514 : tag(MEM), reg(base.code()), offset(off.value)
515 { }
517 Operand (Register base, int32_t off)
518 : tag(MEM), reg(base.code()), offset(off)
519 { }
521 Operand (const Address &addr)
522 : tag(MEM), reg(addr.base.code()), offset(addr.offset)
523 { }
525 Tag getTag() const {
526 return tag;
527 }
529 Register toReg() const {
530 JS_ASSERT(tag == REG);
531 return Register::FromCode(reg);
532 }
534 FloatRegister toFReg() const {
535 JS_ASSERT(tag == FREG);
536 return FloatRegister::FromCode(reg);
537 }
539 void toAddr(Register *r, Imm32 *dest) const {
540 JS_ASSERT(tag == MEM);
541 *r = Register::FromCode(reg);
542 *dest = Imm32(offset);
543 }
544 Address toAddress() const {
545 JS_ASSERT(tag == MEM);
546 return Address(Register::FromCode(reg), offset);
547 }
548 int32_t disp() const {
549 JS_ASSERT(tag == MEM);
550 return offset;
551 }
553 int32_t base() const {
554 JS_ASSERT(tag == MEM);
555 return reg;
556 }
557 Register baseReg() const {
558 JS_ASSERT(tag == MEM);
559 return Register::FromCode(reg);
560 }
561 };
563 void
564 PatchJump(CodeLocationJump &jump_, CodeLocationLabel label);
565 class Assembler;
566 typedef js::jit::AssemblerBuffer<1024, Instruction> MIPSBuffer;
568 class Assembler : public AssemblerShared
569 {
570 public:
572 enum Condition {
573 Equal,
574 NotEqual,
575 Above,
576 AboveOrEqual,
577 Below,
578 BelowOrEqual,
579 GreaterThan,
580 GreaterThanOrEqual,
581 LessThan,
582 LessThanOrEqual,
583 Overflow,
584 Signed,
585 NotSigned,
586 Zero,
587 NonZero,
588 Always,
589 };
591 enum DoubleCondition {
592 // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
593 DoubleOrdered,
594 DoubleEqual,
595 DoubleNotEqual,
596 DoubleGreaterThan,
597 DoubleGreaterThanOrEqual,
598 DoubleLessThan,
599 DoubleLessThanOrEqual,
600 // If either operand is NaN, these conditions always evaluate to true.
601 DoubleUnordered,
602 DoubleEqualOrUnordered,
603 DoubleNotEqualOrUnordered,
604 DoubleGreaterThanOrUnordered,
605 DoubleGreaterThanOrEqualOrUnordered,
606 DoubleLessThanOrUnordered,
607 DoubleLessThanOrEqualOrUnordered
608 };
610 enum FPConditionBit {
611 FCC0 = 0,
612 FCC1,
613 FCC2,
614 FCC3,
615 FCC4,
616 FCC5,
617 FCC6,
618 FCC7
619 };
621 enum FloatFormat {
622 SingleFloat,
623 DoubleFloat
624 };
626 enum JumpOrCall {
627 BranchIsJump,
628 BranchIsCall
629 };
631 enum FloatTestKind {
632 TestForTrue,
633 TestForFalse
634 };
636 // :( this should be protected, but since CodeGenerator
637 // wants to use it, It needs to go out here :(
639 BufferOffset nextOffset() {
640 return m_buffer.nextOffset();
641 }
643 protected:
644 Instruction * editSrc (BufferOffset bo) {
645 return m_buffer.getInst(bo);
646 }
647 public:
648 uint32_t actualOffset(uint32_t) const;
649 uint32_t actualIndex(uint32_t) const;
650 static uint8_t *PatchableJumpAddress(JitCode *code, uint32_t index);
651 protected:
653 // structure for fixing up pc-relative loads/jumps when a the machine code
654 // gets moved (executable copy, gc, etc.)
655 struct RelativePatch
656 {
657 // the offset within the code buffer where the value is loaded that
658 // we want to fix-up
659 BufferOffset offset;
660 void *target;
661 Relocation::Kind kind;
663 RelativePatch(BufferOffset offset, void *target, Relocation::Kind kind)
664 : offset(offset),
665 target(target),
666 kind(kind)
667 { }
668 };
670 js::Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_;
671 js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
672 js::Vector<uint32_t, 8, SystemAllocPolicy> longJumps_;
674 CompactBufferWriter jumpRelocations_;
675 CompactBufferWriter dataRelocations_;
676 CompactBufferWriter relocations_;
677 CompactBufferWriter preBarriers_;
679 bool enoughMemory_;
681 MIPSBuffer m_buffer;
683 public:
684 Assembler()
685 : enoughMemory_(true),
686 m_buffer(),
687 isFinished(false)
688 { }
690 static Condition InvertCondition(Condition cond);
691 static DoubleCondition InvertCondition(DoubleCondition cond);
693 // MacroAssemblers hold onto gcthings, so they are traced by the GC.
694 void trace(JSTracer *trc);
695 void writeRelocation(BufferOffset src) {
696 jumpRelocations_.writeUnsigned(src.getOffset());
697 }
699 // As opposed to x86/x64 version, the data relocation has to be executed
700 // before to recover the pointer, and not after.
701 void writeDataRelocation(const ImmGCPtr &ptr) {
702 if (ptr.value)
703 dataRelocations_.writeUnsigned(nextOffset().getOffset());
704 }
705 void writePrebarrierOffset(CodeOffsetLabel label) {
706 preBarriers_.writeUnsigned(label.offset());
707 }
709 public:
710 static uintptr_t getPointer(uint8_t *);
712 bool oom() const;
714 void setPrinter(Sprinter *sp) {
715 }
717 private:
718 bool isFinished;
719 public:
720 void finish();
721 void executableCopy(void *buffer);
722 void copyJumpRelocationTable(uint8_t *dest);
723 void copyDataRelocationTable(uint8_t *dest);
724 void copyPreBarrierTable(uint8_t *dest);
726 bool addCodeLabel(CodeLabel label);
727 size_t numCodeLabels() const {
728 return codeLabels_.length();
729 }
730 CodeLabel codeLabel(size_t i) {
731 return codeLabels_[i];
732 }
734 // Size of the instruction stream, in bytes.
735 size_t size() const;
736 // Size of the jump relocation table, in bytes.
737 size_t jumpRelocationTableBytes() const;
738 size_t dataRelocationTableBytes() const;
739 size_t preBarrierTableBytes() const;
741 // Size of the data table, in bytes.
742 size_t bytesNeeded() const;
744 // Write a blob of binary into the instruction stream *OR*
745 // into a destination address. If dest is nullptr (the default), then the
746 // instruction gets written into the instruction stream. If dest is not null
747 // it is interpreted as a pointer to the location that we want the
748 // instruction to be written.
749 BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr);
750 // A static variant for the cases where we don't want to have an assembler
751 // object at all. Normally, you would use the dummy (nullptr) object.
752 static void writeInstStatic(uint32_t x, uint32_t *dest);
754 public:
755 BufferOffset align(int alignment);
756 BufferOffset as_nop();
758 // Branch and jump instructions
759 BufferOffset as_bal(BOffImm16 off);
761 InstImm getBranchCode(JumpOrCall jumpOrCall);
762 InstImm getBranchCode(Register s, Register t, Condition c);
763 InstImm getBranchCode(Register s, Condition c);
764 InstImm getBranchCode(FloatTestKind testKind, FPConditionBit fcc);
766 BufferOffset as_j(JOffImm26 off);
767 BufferOffset as_jal(JOffImm26 off);
769 BufferOffset as_jr(Register rs);
770 BufferOffset as_jalr(Register rs);
772 // Arithmetic instructions
773 BufferOffset as_addu(Register rd, Register rs, Register rt);
774 BufferOffset as_addiu(Register rd, Register rs, int32_t j);
775 BufferOffset as_subu(Register rd, Register rs, Register rt);
776 BufferOffset as_mult(Register rs, Register rt);
777 BufferOffset as_multu(Register rs, Register rt);
778 BufferOffset as_div(Register rs, Register rt);
779 BufferOffset as_divu(Register rs, Register rt);
780 BufferOffset as_mul(Register rd, Register rs, Register rt);
782 // Logical instructions
783 BufferOffset as_and(Register rd, Register rs, Register rt);
784 BufferOffset as_or(Register rd, Register rs, Register rt);
785 BufferOffset as_xor(Register rd, Register rs, Register rt);
786 BufferOffset as_nor(Register rd, Register rs, Register rt);
788 BufferOffset as_andi(Register rd, Register rs, int32_t j);
789 BufferOffset as_ori(Register rd, Register rs, int32_t j);
790 BufferOffset as_xori(Register rd, Register rs, int32_t j);
791 BufferOffset as_lui(Register rd, int32_t j);
793 // Shift instructions
794 // as_sll(zero, zero, x) instructions are reserved as nop
795 BufferOffset as_sll(Register rd, Register rt, uint16_t sa);
796 BufferOffset as_sllv(Register rd, Register rt, Register rs);
797 BufferOffset as_srl(Register rd, Register rt, uint16_t sa);
798 BufferOffset as_srlv(Register rd, Register rt, Register rs);
799 BufferOffset as_sra(Register rd, Register rt, uint16_t sa);
800 BufferOffset as_srav(Register rd, Register rt, Register rs);
801 BufferOffset as_rotr(Register rd, Register rt, uint16_t sa);
802 BufferOffset as_rotrv(Register rd, Register rt, Register rs);
804 // Load and store instructions
805 BufferOffset as_lb(Register rd, Register rs, int16_t off);
806 BufferOffset as_lbu(Register rd, Register rs, int16_t off);
807 BufferOffset as_lh(Register rd, Register rs, int16_t off);
808 BufferOffset as_lhu(Register rd, Register rs, int16_t off);
809 BufferOffset as_lw(Register rd, Register rs, int16_t off);
810 BufferOffset as_lwl(Register rd, Register rs, int16_t off);
811 BufferOffset as_lwr(Register rd, Register rs, int16_t off);
812 BufferOffset as_sb(Register rd, Register rs, int16_t off);
813 BufferOffset as_sh(Register rd, Register rs, int16_t off);
814 BufferOffset as_sw(Register rd, Register rs, int16_t off);
815 BufferOffset as_swl(Register rd, Register rs, int16_t off);
816 BufferOffset as_swr(Register rd, Register rs, int16_t off);
818 // Move from HI/LO register.
819 BufferOffset as_mfhi(Register rd);
820 BufferOffset as_mflo(Register rd);
822 // Set on less than.
823 BufferOffset as_slt(Register rd, Register rs, Register rt);
824 BufferOffset as_sltu(Register rd, Register rs, Register rt);
825 BufferOffset as_slti(Register rd, Register rs, int32_t j);
826 BufferOffset as_sltiu(Register rd, Register rs, uint32_t j);
828 // Conditional move.
829 BufferOffset as_movz(Register rd, Register rs, Register rt);
830 BufferOffset as_movn(Register rd, Register rs, Register rt);
831 BufferOffset as_movt(Register rd, Register rs, uint16_t cc = 0);
832 BufferOffset as_movf(Register rd, Register rs, uint16_t cc = 0);
834 // Bit twiddling.
835 BufferOffset as_clz(Register rd, Register rs, Register rt = Register::FromCode(0));
836 BufferOffset as_ins(Register rt, Register rs, uint16_t pos, uint16_t size);
837 BufferOffset as_ext(Register rt, Register rs, uint16_t pos, uint16_t size);
839 // FP instructions
841 // Use these two functions only when you are sure address is aligned.
842 // Otherwise, use ma_ld and ma_sd.
843 BufferOffset as_ld(FloatRegister fd, Register base, int32_t off);
844 BufferOffset as_sd(FloatRegister fd, Register base, int32_t off);
846 BufferOffset as_ls(FloatRegister fd, Register base, int32_t off);
847 BufferOffset as_ss(FloatRegister fd, Register base, int32_t off);
849 BufferOffset as_movs(FloatRegister fd, FloatRegister fs);
850 BufferOffset as_movd(FloatRegister fd, FloatRegister fs);
852 BufferOffset as_mtc1(Register rt, FloatRegister fs);
853 BufferOffset as_mfc1(Register rt, FloatRegister fs);
855 protected:
856 // This is used to access the odd regiter form the pair of single
857 // precision registers that make one double register.
858 FloatRegister getOddPair(FloatRegister reg) {
859 JS_ASSERT(reg.code() % 2 == 0);
860 return FloatRegister::FromCode(reg.code() + 1);
861 }
863 public:
864 // FP convert instructions
865 BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs);
866 BufferOffset as_floorws(FloatRegister fd, FloatRegister fs);
867 BufferOffset as_roundws(FloatRegister fd, FloatRegister fs);
868 BufferOffset as_truncws(FloatRegister fd, FloatRegister fs);
870 BufferOffset as_ceilwd(FloatRegister fd, FloatRegister fs);
871 BufferOffset as_floorwd(FloatRegister fd, FloatRegister fs);
872 BufferOffset as_roundwd(FloatRegister fd, FloatRegister fs);
873 BufferOffset as_truncwd(FloatRegister fd, FloatRegister fs);
875 BufferOffset as_cvtdl(FloatRegister fd, FloatRegister fs);
876 BufferOffset as_cvtds(FloatRegister fd, FloatRegister fs);
877 BufferOffset as_cvtdw(FloatRegister fd, FloatRegister fs);
878 BufferOffset as_cvtld(FloatRegister fd, FloatRegister fs);
879 BufferOffset as_cvtls(FloatRegister fd, FloatRegister fs);
880 BufferOffset as_cvtsd(FloatRegister fd, FloatRegister fs);
881 BufferOffset as_cvtsl(FloatRegister fd, FloatRegister fs);
882 BufferOffset as_cvtsw(FloatRegister fd, FloatRegister fs);
883 BufferOffset as_cvtwd(FloatRegister fd, FloatRegister fs);
884 BufferOffset as_cvtws(FloatRegister fd, FloatRegister fs);
886 // FP arithmetic instructions
887 BufferOffset as_adds(FloatRegister fd, FloatRegister fs, FloatRegister ft);
888 BufferOffset as_addd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
889 BufferOffset as_subs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
890 BufferOffset as_subd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
892 BufferOffset as_abss(FloatRegister fd, FloatRegister fs);
893 BufferOffset as_absd(FloatRegister fd, FloatRegister fs);
894 BufferOffset as_negd(FloatRegister fd, FloatRegister fs);
896 BufferOffset as_muls(FloatRegister fd, FloatRegister fs, FloatRegister ft);
897 BufferOffset as_muld(FloatRegister fd, FloatRegister fs, FloatRegister ft);
898 BufferOffset as_divs(FloatRegister fd, FloatRegister fs, FloatRegister ft);
899 BufferOffset as_divd(FloatRegister fd, FloatRegister fs, FloatRegister ft);
900 BufferOffset as_sqrts(FloatRegister fd, FloatRegister fs);
901 BufferOffset as_sqrtd(FloatRegister fd, FloatRegister fs);
903 // FP compare instructions
904 BufferOffset as_cf(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
905 FPConditionBit fcc = FCC0);
906 BufferOffset as_cun(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
907 FPConditionBit fcc = FCC0);
908 BufferOffset as_ceq(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
909 FPConditionBit fcc = FCC0);
910 BufferOffset as_cueq(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
911 FPConditionBit fcc = FCC0);
912 BufferOffset as_colt(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
913 FPConditionBit fcc = FCC0);
914 BufferOffset as_cult(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
915 FPConditionBit fcc = FCC0);
916 BufferOffset as_cole(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
917 FPConditionBit fcc = FCC0);
918 BufferOffset as_cule(FloatFormat fmt, FloatRegister fs, FloatRegister ft,
919 FPConditionBit fcc = FCC0);
921 // label operations
922 void bind(Label *label, BufferOffset boff = BufferOffset());
923 void bind(RepatchLabel *label);
924 uint32_t currentOffset() {
925 return nextOffset().getOffset();
926 }
927 void retarget(Label *label, Label *target);
928 void Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address);
930 // See Bind
931 size_t labelOffsetToPatchOffset(size_t offset) {
932 return actualOffset(offset);
933 }
935 void call(Label *label);
936 void call(void *target);
938 void as_break(uint32_t code);
940 public:
941 static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
942 static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
944 protected:
945 InstImm invertBranch(InstImm branch, BOffImm16 skipOffset);
946 void bind(InstImm *inst, uint32_t branch, uint32_t target);
947 void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) {
948 enoughMemory_ &= jumps_.append(RelativePatch(src, target.value, kind));
949 if (kind == Relocation::JITCODE)
950 writeRelocation(src);
951 }
953 void addLongJump(BufferOffset src) {
954 enoughMemory_ &= longJumps_.append(src.getOffset());
955 }
957 public:
958 size_t numLongJumps() const {
959 return longJumps_.length();
960 }
961 uint32_t longJump(size_t i) {
962 return longJumps_[i];
963 }
965 // Copy the assembly code to the given buffer, and perform any pending
966 // relocations relying on the target address.
967 void executableCopy(uint8_t *buffer);
969 void flushBuffer() {
970 }
972 static uint32_t patchWrite_NearCallSize();
973 static uint32_t nopSize() { return 4; }
975 static uint32_t extractLuiOriValue(Instruction *inst0, Instruction *inst1);
976 static void updateLuiOriValue(Instruction *inst0, Instruction *inst1, uint32_t value);
977 static void writeLuiOriInstructions(Instruction *inst, Instruction *inst1,
978 Register reg, uint32_t value);
980 static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
981 static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
982 PatchedImmPtr expectedValue);
983 static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
984 ImmPtr expectedValue);
985 static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
986 static uint32_t alignDoubleArg(uint32_t offset) {
987 return (offset + 1U) &~ 1U;
988 }
990 static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
992 static void ToggleToJmp(CodeLocationLabel inst_);
993 static void ToggleToCmp(CodeLocationLabel inst_);
995 static void ToggleCall(CodeLocationLabel inst_, bool enabled);
997 static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
998 void processCodeLabels(uint8_t *rawCode);
1000 bool bailed() {
1001 return m_buffer.bail();
1002 }
1003 }; // Assembler
1005 // An Instruction is a structure for both encoding and decoding any and all
1006 // MIPS instructions.
1007 class Instruction
1008 {
1009 protected:
1010 // sll zero, zero, 0
1011 static const uint32_t NopInst = 0x00000000;
1013 uint32_t data;
1015 // Standard constructor
1016 Instruction (uint32_t data_) : data(data_) { }
1018 // You should never create an instruction directly. You should create a
1019 // more specific instruction which will eventually call one of these
1020 // constructors for you.
1021 public:
1022 uint32_t encode() const {
1023 return data;
1024 }
1026 void makeNop() {
1027 data = NopInst;
1028 }
1030 void setData(uint32_t data) {
1031 this->data = data;
1032 }
1034 const Instruction & operator=(const Instruction &src) {
1035 data = src.data;
1036 return *this;
1037 }
1039 // Extract the one particular bit.
1040 uint32_t extractBit(uint32_t bit) {
1041 return (encode() >> bit) & 1;
1042 }
1043 // Extract a bit field out of the instruction
1044 uint32_t extractBitField(uint32_t hi, uint32_t lo) {
1045 return (encode() >> lo) & ((2 << (hi - lo)) - 1);
1046 }
1047 // Since all MIPS instructions have opcode, the opcode
1048 // extractor resides in the base class.
1049 uint32_t extractOpcode() {
1050 return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift);
1051 }
1052 // Return the fields at their original place in the instruction encoding.
1053 Opcode OpcodeFieldRaw() const {
1054 return static_cast<Opcode>(encode() & OpcodeMask);
1055 }
1057 // Get the next instruction in the instruction stream.
1058 // This does neat things like ignoreconstant pools and their guards.
1059 Instruction *next();
1061 // Sometimes, an api wants a uint32_t (or a pointer to it) rather than
1062 // an instruction. raw() just coerces this into a pointer to a uint32_t
1063 const uint32_t *raw() const { return &data; }
1064 uint32_t size() const { return 4; }
1065 }; // Instruction
1067 // make sure that it is the right size
1068 static_assert(sizeof(Instruction) == 4, "Size of Instruction class has to be 4 bytes.");
1070 class InstNOP : public Instruction
1071 {
1072 public:
1073 InstNOP()
1074 : Instruction(NopInst)
1075 { }
1077 };
1079 // Class for register type instructions.
1080 class InstReg : public Instruction
1081 {
1082 public:
1083 InstReg(Opcode op, Register rd, FunctionField ff)
1084 : Instruction(op | RD(rd) | ff)
1085 { }
1086 InstReg(Opcode op, Register rs, Register rt, FunctionField ff)
1087 : Instruction(op | RS(rs) | RT(rt) | ff)
1088 { }
1089 InstReg(Opcode op, Register rs, Register rt, Register rd, FunctionField ff)
1090 : Instruction(op | RS(rs) | RT(rt) | RD(rd) | ff)
1091 { }
1092 InstReg(Opcode op, Register rs, Register rt, Register rd, uint32_t sa, FunctionField ff)
1093 : Instruction(op | RS(rs) | RT(rt) | RD(rd) | SA(sa) | ff)
1094 { }
1095 InstReg(Opcode op, RSField rs, Register rt, Register rd, uint32_t sa, FunctionField ff)
1096 : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff)
1097 { }
1098 InstReg(Opcode op, Register rs, RTField rt, Register rd, uint32_t sa, FunctionField ff)
1099 : Instruction(op | RS(rs) | rt | RD(rd) | SA(sa) | ff)
1100 { }
1101 InstReg(Opcode op, Register rs, uint32_t cc, Register rd, uint32_t sa, FunctionField ff)
1102 : Instruction(op | RS(rs) | cc | RD(rd) | SA(sa) | ff)
1103 { }
1104 InstReg(Opcode op, uint32_t code, FunctionField ff)
1105 : Instruction(op | code | ff)
1106 { }
1107 // for float point
1108 InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd)
1109 : Instruction(op | rs | RT(rt) | RD(rd))
1110 { }
1111 InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd, uint32_t sa, FunctionField ff)
1112 : Instruction(op | rs | RT(rt) | RD(rd) | SA(sa) | ff)
1113 { }
1114 InstReg(Opcode op, RSField rs, Register rt, FloatRegister fs, FloatRegister fd, FunctionField ff)
1115 : Instruction(op | rs | RT(rt) | RD(fs) | SA(fd) | ff)
1116 { }
1117 InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fs, FloatRegister fd, FunctionField ff)
1118 : Instruction(op | rs | RT(ft) | RD(fs) | SA(fd) | ff)
1119 { }
1120 InstReg(Opcode op, RSField rs, FloatRegister ft, FloatRegister fd, uint32_t sa, FunctionField ff)
1121 : Instruction(op | rs | RT(ft) | RD(fd) | SA(sa) | ff)
1122 { }
1124 uint32_t extractRS () {
1125 return extractBitField(RSShift + RSBits - 1, RSShift);
1126 }
1127 uint32_t extractRT () {
1128 return extractBitField(RTShift + RTBits - 1, RTShift);
1129 }
1130 uint32_t extractRD () {
1131 return extractBitField(RDShift + RDBits - 1, RDShift);
1132 }
1133 uint32_t extractSA () {
1134 return extractBitField(SAShift + SABits - 1, SAShift);
1135 }
1136 uint32_t extractFunctionField () {
1137 return extractBitField(FunctionShift + FunctionBits - 1, FunctionShift);
1138 }
1139 };
1141 // Class for branch, load and store instructions with immediate offset.
1142 class InstImm : public Instruction
1143 {
1144 public:
1145 void extractImm16(BOffImm16 *dest);
1147 InstImm(Opcode op, Register rs, Register rt, BOffImm16 off)
1148 : Instruction(op | RS(rs) | RT(rt) | off.encode())
1149 { }
1150 InstImm(Opcode op, Register rs, RTField rt, BOffImm16 off)
1151 : Instruction(op | RS(rs) | rt | off.encode())
1152 { }
1153 InstImm(Opcode op, RSField rs, uint32_t cc, BOffImm16 off)
1154 : Instruction(op | rs | cc | off.encode())
1155 { }
1156 InstImm(Opcode op, Register rs, Register rt, Imm16 off)
1157 : Instruction(op | RS(rs) | RT(rt) | off.encode())
1158 { }
1159 InstImm(uint32_t raw)
1160 : Instruction(raw)
1161 { }
1162 // For floating-point loads and stores.
1163 InstImm(Opcode op, Register rs, FloatRegister rt, Imm16 off)
1164 : Instruction(op | RS(rs) | RT(rt) | off.encode())
1165 { }
1167 uint32_t extractOpcode() {
1168 return extractBitField(OpcodeShift + OpcodeBits - 1, OpcodeShift);
1169 }
1170 void setOpcode(Opcode op) {
1171 data = (data & ~OpcodeMask) | op;
1172 }
1173 uint32_t extractRS() {
1174 return extractBitField(RSShift + RSBits - 1, RSShift);
1175 }
1176 uint32_t extractRT() {
1177 return extractBitField(RTShift + RTBits - 1, RTShift);
1178 }
1179 void setRT(RTField rt) {
1180 data = (data & ~RTMask) | rt;
1181 }
1182 uint32_t extractImm16Value() {
1183 return extractBitField(Imm16Shift + Imm16Bits - 1, Imm16Shift);
1184 }
1185 void setBOffImm16(BOffImm16 off) {
1186 // Reset immediate field and replace it
1187 data = (data & ~Imm16Mask) | off.encode();
1188 }
1189 void setImm16(Imm16 off) {
1190 // Reset immediate field and replace it
1191 data = (data & ~Imm16Mask) | off.encode();
1192 }
1193 };
1195 // Class for Jump type instructions.
1196 class InstJump : public Instruction
1197 {
1198 public:
1199 InstJump(Opcode op, JOffImm26 off)
1200 : Instruction(op | off.encode())
1201 { }
1203 uint32_t extractImm26Value() {
1204 return extractBitField(Imm26Shift + Imm26Bits - 1, Imm26Shift);
1205 }
1206 };
1208 static const uint32_t NumIntArgRegs = 4;
1210 static inline bool
1211 GetIntArgReg(uint32_t usedArgSlots, Register *out)
1212 {
1213 if (usedArgSlots < NumIntArgRegs) {
1214 *out = Register::FromCode(a0.code() + usedArgSlots);
1215 return true;
1216 }
1217 return false;
1218 }
1220 // Get a register in which we plan to put a quantity that will be used as an
1221 // integer argument. This differs from GetIntArgReg in that if we have no more
1222 // actual argument registers to use we will fall back on using whatever
1223 // CallTempReg* don't overlap the argument registers, and only fail once those
1224 // run out too.
1225 static inline bool
1226 GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out)
1227 {
1228 // NOTE: We can't properly determine which regs are used if there are
1229 // float arguments. If this is needed, we will have to guess.
1230 JS_ASSERT(usedFloatArgs == 0);
1232 if (GetIntArgReg(usedIntArgs, out))
1233 return true;
1234 // Unfortunately, we have to assume things about the point at which
1235 // GetIntArgReg returns false, because we need to know how many registers it
1236 // can allocate.
1237 usedIntArgs -= NumIntArgRegs;
1238 if (usedIntArgs >= NumCallTempNonArgRegs)
1239 return false;
1240 *out = CallTempNonArgRegs[usedIntArgs];
1241 return true;
1242 }
1244 static inline uint32_t
1245 GetArgStackDisp(uint32_t usedArgSlots)
1246 {
1247 JS_ASSERT(usedArgSlots >= NumIntArgRegs);
1248 // Even register arguments have place reserved on stack.
1249 return usedArgSlots * sizeof(intptr_t);
1250 }
1252 } // namespace jit
1253 } // namespace js
1255 #endif /* jit_mips_Assembler_mips_h */