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_MacroAssembler_mips_h
8 #define jit_mips_MacroAssembler_mips_h
10 #include "jsopcode.h"
12 #include "jit/IonCaches.h"
13 #include "jit/IonFrames.h"
14 #include "jit/mips/Assembler-mips.h"
15 #include "jit/MoveResolver.h"
17 namespace js {
18 namespace jit {
20 enum LoadStoreSize
21 {
22 SizeByte = 8,
23 SizeHalfWord = 16,
24 SizeWord = 32,
25 SizeDouble = 64
26 };
28 enum LoadStoreExtension
29 {
30 ZeroExtend = 0,
31 SignExtend = 1
32 };
34 enum JumpKind
35 {
36 LongJump = 0,
37 ShortJump = 1
38 };
40 struct ImmTag : public Imm32
41 {
42 ImmTag(JSValueTag mask)
43 : Imm32(int32_t(mask))
44 { }
45 };
47 struct ImmType : public ImmTag
48 {
49 ImmType(JSValueType type)
50 : ImmTag(JSVAL_TYPE_TO_TAG(type))
51 { }
52 };
54 static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data);
55 static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0);
57 static Register CallReg = t9;
58 static const int defaultShift = 3;
59 static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong");
61 class MacroAssemblerMIPS : public Assembler
62 {
63 public:
65 void convertBoolToInt32(Register source, Register dest);
66 void convertInt32ToDouble(const Register &src, const FloatRegister &dest);
67 void convertInt32ToDouble(const Address &src, FloatRegister dest);
68 void convertUInt32ToDouble(const Register &src, const FloatRegister &dest);
69 void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest);
70 void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest);
71 void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail);
72 void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail,
73 bool negativeZeroCheck = true);
74 void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail,
75 bool negativeZeroCheck = true);
77 void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest);
78 void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail);
79 void convertInt32ToFloat32(const Register &src, const FloatRegister &dest);
80 void convertInt32ToFloat32(const Address &src, FloatRegister dest);
83 void addDouble(FloatRegister src, FloatRegister dest);
84 void subDouble(FloatRegister src, FloatRegister dest);
85 void mulDouble(FloatRegister src, FloatRegister dest);
86 void divDouble(FloatRegister src, FloatRegister dest);
88 void negateDouble(FloatRegister reg);
89 void inc64(AbsoluteAddress dest);
91 public:
93 void ma_move(Register rd, Register rs);
95 void ma_li(Register dest, const ImmGCPtr &ptr);
97 void ma_li(const Register &dest, AbsoluteLabel *label);
99 void ma_li(Register dest, Imm32 imm);
100 void ma_liPatchable(Register dest, Imm32 imm);
101 void ma_liPatchable(Register dest, ImmPtr imm);
103 // Shift operations
104 void ma_sll(Register rd, Register rt, Imm32 shift);
105 void ma_srl(Register rd, Register rt, Imm32 shift);
106 void ma_sra(Register rd, Register rt, Imm32 shift);
107 void ma_ror(Register rd, Register rt, Imm32 shift);
108 void ma_rol(Register rd, Register rt, Imm32 shift);
110 void ma_sll(Register rd, Register rt, Register shift);
111 void ma_srl(Register rd, Register rt, Register shift);
112 void ma_sra(Register rd, Register rt, Register shift);
113 void ma_ror(Register rd, Register rt, Register shift);
114 void ma_rol(Register rd, Register rt, Register shift);
116 // Negate
117 void ma_negu(Register rd, Register rs);
119 void ma_not(Register rd, Register rs);
121 // and
122 void ma_and(Register rd, Register rs);
123 void ma_and(Register rd, Register rs, Register rt);
124 void ma_and(Register rd, Imm32 imm);
125 void ma_and(Register rd, Register rs, Imm32 imm);
127 // or
128 void ma_or(Register rd, Register rs);
129 void ma_or(Register rd, Register rs, Register rt);
130 void ma_or(Register rd, Imm32 imm);
131 void ma_or(Register rd, Register rs, Imm32 imm);
133 // xor
134 void ma_xor(Register rd, Register rs);
135 void ma_xor(Register rd, Register rs, Register rt);
136 void ma_xor(Register rd, Imm32 imm);
137 void ma_xor(Register rd, Register rs, Imm32 imm);
139 // load
140 void ma_load(const Register &dest, Address address, LoadStoreSize size = SizeWord,
141 LoadStoreExtension extension = SignExtend);
142 void ma_load(const Register &dest, const BaseIndex &src, LoadStoreSize size = SizeWord,
143 LoadStoreExtension extension = SignExtend);
145 // store
146 void ma_store(const Register &data, Address address, LoadStoreSize size = SizeWord,
147 LoadStoreExtension extension = SignExtend);
148 void ma_store(const Register &data, const BaseIndex &dest, LoadStoreSize size = SizeWord,
149 LoadStoreExtension extension = SignExtend);
150 void ma_store(const Imm32 &imm, const BaseIndex &dest, LoadStoreSize size = SizeWord,
151 LoadStoreExtension extension = SignExtend);
153 void computeScaledAddress(const BaseIndex &address, Register dest);
155 void computeEffectiveAddress(const Address &address, Register dest) {
156 ma_addu(dest, address.base, Imm32(address.offset));
157 }
159 void computeEffectiveAddress(const BaseIndex &address, Register dest) {
160 computeScaledAddress(address, dest);
161 if (address.offset) {
162 ma_addu(dest, dest, Imm32(address.offset));
163 }
164 }
166 // arithmetic based ops
167 // add
168 void ma_addu(Register rd, Register rs, Imm32 imm);
169 void ma_addu(Register rd, Register rs);
170 void ma_addu(Register rd, Imm32 imm);
171 void ma_addTestOverflow(Register rd, Register rs, Register rt, Label *overflow);
172 void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow);
174 // subtract
175 void ma_subu(Register rd, Register rs, Register rt);
176 void ma_subu(Register rd, Register rs, Imm32 imm);
177 void ma_subu(Register rd, Imm32 imm);
178 void ma_subTestOverflow(Register rd, Register rs, Register rt, Label *overflow);
179 void ma_subTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow);
181 // multiplies. For now, there are only few that we care about.
182 void ma_mult(Register rs, Imm32 imm);
183 void ma_mul_branch_overflow(Register rd, Register rs, Register rt, Label *overflow);
184 void ma_mul_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow);
186 // divisions
187 void ma_div_branch_overflow(Register rd, Register rs, Register rt, Label *overflow);
188 void ma_div_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow);
190 // fast mod, uses scratch registers, and thus needs to be in the assembler
191 // implicitly assumes that we can overwrite dest at the beginning of the sequence
192 void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift,
193 Label *negZero = nullptr);
195 // memory
196 // shortcut for when we know we're transferring 32 bits of data
197 void ma_lw(Register data, Address address);
199 void ma_sw(Register data, Address address);
200 void ma_sw(Imm32 imm, Address address);
202 void ma_pop(Register r);
203 void ma_push(Register r);
205 // branches when done from within mips-specific code
206 void ma_b(Register lhs, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump);
207 void ma_b(Register lhs, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
208 void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump);
209 void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
210 void ma_b(Label *l, JumpKind jumpKind = LongJump);
211 void ma_bal(Label *l, JumpKind jumpKind = LongJump);
213 // fp instructions
214 void ma_lis(FloatRegister dest, float value);
215 void ma_lid(FloatRegister dest, double value);
216 void ma_liNegZero(FloatRegister dest);
218 void ma_mv(FloatRegister src, ValueOperand dest);
219 void ma_mv(ValueOperand src, FloatRegister dest);
221 void ma_ls(FloatRegister fd, Address address);
222 void ma_ld(FloatRegister fd, Address address);
223 void ma_sd(FloatRegister fd, Address address);
224 void ma_sd(FloatRegister fd, BaseIndex address);
225 void ma_ss(FloatRegister fd, Address address);
226 void ma_ss(FloatRegister fd, BaseIndex address);
228 void ma_pop(FloatRegister fs);
229 void ma_push(FloatRegister fs);
231 //FP branches
232 void ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c,
233 JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
234 void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c,
235 JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
238 // These fuctions abstract the access to high part of the double precision
239 // float register. It is intended to work on both 32 bit and 64 bit
240 // floating point coprocessor.
241 // :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1
242 void moveToDoubleHi(Register src, FloatRegister dest) {
243 as_mtc1(src, getOddPair(dest));
244 }
245 void moveFromDoubleHi(FloatRegister src, Register dest) {
246 as_mfc1(dest, getOddPair(src));
247 }
249 void moveToDoubleLo(Register src, FloatRegister dest) {
250 as_mtc1(src, dest);
251 }
252 void moveFromDoubleLo(FloatRegister src, Register dest) {
253 as_mfc1(dest, src);
254 }
256 void moveToFloat32(Register src, FloatRegister dest) {
257 as_mtc1(src, dest);
258 }
259 void moveFromFloat32(FloatRegister src, Register dest) {
260 as_mfc1(dest, src);
261 }
263 protected:
264 void branchWithCode(InstImm code, Label *label, JumpKind jumpKind);
265 Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c);
267 void compareFloatingPoint(FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
268 DoubleCondition c, FloatTestKind *testKind,
269 FPConditionBit fcc = FCC0);
271 public:
272 // calls an Ion function, assumes that the stack is untouched (8 byte alinged)
273 void ma_callIon(const Register reg);
274 // callso an Ion function, assuming that sp has already been decremented
275 void ma_callIonNoPush(const Register reg);
276 // calls an ion function, assuming that the stack is currently not 8 byte aligned
277 void ma_callIonHalfPush(const Register reg);
279 void ma_call(ImmPtr dest);
281 void ma_jump(ImmPtr dest);
283 void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c);
284 void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c);
285 void ma_cmp_set(Register rd, Register rs, Address addr, Condition c);
286 void ma_cmp_set(Register dst, Address lhs, Register imm, Condition c);
287 void ma_cmp_set_double(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c);
288 void ma_cmp_set_float32(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c);
289 };
291 class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
292 {
293 // Number of bytes the stack is adjusted inside a call to C. Calls to C may
294 // not be nested.
295 bool inCall_;
296 uint32_t args_;
297 // The actual number of arguments that were passed, used to assert that
298 // the initial number of arguments declared was correct.
299 uint32_t passedArgs_;
301 uint32_t usedArgSlots_;
302 MoveOp::Type firstArgType;
304 bool dynamicAlignment_;
306 bool enoughMemory_;
307 // Compute space needed for the function call and set the properties of the
308 // callee. It returns the space which has to be allocated for calling the
309 // function.
310 //
311 // arg Number of arguments of the function.
312 void setupABICall(uint32_t arg);
314 protected:
315 MoveResolver moveResolver_;
317 // Extra bytes currently pushed onto the frame beyond frameDepth_. This is
318 // needed to compute offsets to stack slots while temporary space has been
319 // reserved for unexpected spills or C++ function calls. It is maintained
320 // by functions which track stack alignment, which for clear distinction
321 // use StudlyCaps (for example, Push, Pop).
322 uint32_t framePushed_;
323 void adjustFrame(int value) {
324 setFramePushed(framePushed_ + value);
325 }
326 public:
327 MacroAssemblerMIPSCompat()
328 : inCall_(false),
329 enoughMemory_(true),
330 framePushed_(0)
331 { }
332 bool oom() const {
333 return Assembler::oom();
334 }
336 public:
337 using MacroAssemblerMIPS::call;
339 void j(Label *dest) {
340 ma_b(dest);
341 }
343 void mov(Register src, Register dest) {
344 as_or(dest, src, zero);
345 }
346 void mov(ImmWord imm, Register dest) {
347 ma_li(dest, Imm32(imm.value));
348 }
349 void mov(ImmPtr imm, Register dest) {
350 mov(ImmWord(uintptr_t(imm.value)), dest);
351 }
352 void mov(Register src, Address dest) {
353 MOZ_ASSUME_UNREACHABLE("NYI-IC");
354 }
355 void mov(Address src, Register dest) {
356 MOZ_ASSUME_UNREACHABLE("NYI-IC");
357 }
359 void call(const Register reg) {
360 as_jalr(reg);
361 as_nop();
362 }
364 void call(Label *label) {
365 // for now, assume that it'll be nearby?
366 ma_bal(label);
367 }
369 void call(ImmWord imm) {
370 call(ImmPtr((void*)imm.value));
371 }
372 void call(ImmPtr imm) {
373 BufferOffset bo = m_buffer.nextOffset();
374 addPendingJump(bo, imm, Relocation::HARDCODED);
375 ma_call(imm);
376 }
377 void call(AsmJSImmPtr imm) {
378 movePtr(imm, CallReg);
379 call(CallReg);
380 }
381 void call(JitCode *c) {
382 BufferOffset bo = m_buffer.nextOffset();
383 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
384 ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
385 ma_callIonHalfPush(ScratchRegister);
386 }
387 void branch(JitCode *c) {
388 BufferOffset bo = m_buffer.nextOffset();
389 addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE);
390 ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw()));
391 as_jr(ScratchRegister);
392 as_nop();
393 }
394 void branch(const Register reg) {
395 as_jr(reg);
396 as_nop();
397 }
398 void nop() {
399 as_nop();
400 }
401 void ret() {
402 ma_pop(ra);
403 as_jr(ra);
404 as_nop();
405 }
406 void retn(Imm32 n) {
407 // pc <- [sp]; sp += n
408 ma_lw(ra, Address(StackPointer, 0));
409 ma_addu(StackPointer, StackPointer, n);
410 as_jr(ra);
411 as_nop();
412 }
413 void push(Imm32 imm) {
414 ma_li(ScratchRegister, imm);
415 ma_push(ScratchRegister);
416 }
417 void push(ImmWord imm) {
418 ma_li(ScratchRegister, Imm32(imm.value));
419 ma_push(ScratchRegister);
420 }
421 void push(ImmGCPtr imm) {
422 ma_li(ScratchRegister, imm);
423 ma_push(ScratchRegister);
424 }
425 void push(const Address &address) {
426 ma_lw(ScratchRegister, address);
427 ma_push(ScratchRegister);
428 }
429 void push(const Register ®) {
430 ma_push(reg);
431 }
432 void push(const FloatRegister ®) {
433 ma_push(reg);
434 }
435 void pop(const Register ®) {
436 ma_pop(reg);
437 }
438 void pop(const FloatRegister ®) {
439 ma_pop(reg);
440 }
442 // Emit a branch that can be toggled to a non-operation. On MIPS we use
443 // "andi" instruction to toggle the branch.
444 // See ToggleToJmp(), ToggleToCmp().
445 CodeOffsetLabel toggledJump(Label *label);
447 // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch
448 // this instruction.
449 CodeOffsetLabel toggledCall(JitCode *target, bool enabled);
451 static size_t ToggledCallSize() {
452 // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall
453 return 4 * sizeof(uint32_t);
454 }
456 CodeOffsetLabel pushWithPatch(ImmWord imm) {
457 CodeOffsetLabel label = movWithPatch(imm, ScratchRegister);
458 ma_push(ScratchRegister);
459 return label;
460 }
462 CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) {
463 CodeOffsetLabel label = currentOffset();
464 ma_liPatchable(dest, Imm32(imm.value));
465 return label;
466 }
467 CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) {
468 return movWithPatch(ImmWord(uintptr_t(imm.value)), dest);
469 }
471 void jump(Label *label) {
472 ma_b(label);
473 }
474 void jump(Register reg) {
475 as_jr(reg);
476 as_nop();
477 }
478 void jump(const Address &address) {
479 ma_lw(ScratchRegister, address);
480 as_jr(ScratchRegister);
481 as_nop();
482 }
484 void neg32(Register reg) {
485 ma_negu(reg, reg);
486 }
487 void negl(Register reg) {
488 ma_negu(reg, reg);
489 }
491 // Returns the register containing the type tag.
492 Register splitTagForTest(const ValueOperand &value) {
493 return value.typeReg();
494 }
496 void branchTestGCThing(Condition cond, const Address &address, Label *label);
497 void branchTestGCThing(Condition cond, const BaseIndex &src, Label *label);
499 void branchTestPrimitive(Condition cond, const ValueOperand &value, Label *label);
500 void branchTestPrimitive(Condition cond, const Register &tag, Label *label);
502 void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label);
503 void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value,
504 Label *label);
506 // unboxing code
507 void unboxInt32(const ValueOperand &operand, const Register &dest);
508 void unboxInt32(const Address &src, const Register &dest);
509 void unboxBoolean(const ValueOperand &operand, const Register &dest);
510 void unboxBoolean(const Address &src, const Register &dest);
511 void unboxDouble(const ValueOperand &operand, const FloatRegister &dest);
512 void unboxDouble(const Address &src, const FloatRegister &dest);
513 void unboxString(const ValueOperand &operand, const Register &dest);
514 void unboxString(const Address &src, const Register &dest);
515 void unboxObject(const ValueOperand &src, const Register &dest);
516 void unboxValue(const ValueOperand &src, AnyRegister dest);
517 void unboxPrivate(const ValueOperand &src, Register dest);
519 void notBoolean(const ValueOperand &val) {
520 as_xori(val.payloadReg(), val.payloadReg(), 1);
521 }
523 // boxing code
524 void boxDouble(const FloatRegister &src, const ValueOperand &dest);
525 void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest);
527 // Extended unboxing API. If the payload is already in a register, returns
528 // that register. Otherwise, provides a move to the given scratch register,
529 // and returns that.
530 Register extractObject(const Address &address, Register scratch);
531 Register extractObject(const ValueOperand &value, Register scratch) {
532 return value.payloadReg();
533 }
534 Register extractInt32(const ValueOperand &value, Register scratch) {
535 return value.payloadReg();
536 }
537 Register extractBoolean(const ValueOperand &value, Register scratch) {
538 return value.payloadReg();
539 }
540 Register extractTag(const Address &address, Register scratch);
541 Register extractTag(const BaseIndex &address, Register scratch);
542 Register extractTag(const ValueOperand &value, Register scratch) {
543 return value.typeReg();
544 }
546 void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest);
547 void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest);
548 void loadInt32OrDouble(const Address &address, const FloatRegister &dest);
549 void loadInt32OrDouble(Register base, Register index,
550 const FloatRegister &dest, int32_t shift = defaultShift);
551 void loadConstantDouble(double dp, const FloatRegister &dest);
553 void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest);
554 void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest);
555 void loadConstantFloat32(float f, const FloatRegister &dest);
557 void branchTestInt32(Condition cond, const ValueOperand &value, Label *label);
558 void branchTestInt32(Condition cond, const Register &tag, Label *label);
559 void branchTestInt32(Condition cond, const Address &address, Label *label);
560 void branchTestInt32(Condition cond, const BaseIndex &src, Label *label);
562 void branchTestBoolean(Condition cond, const ValueOperand &value, Label *label);
563 void branchTestBoolean(Condition cond, const Register &tag, Label *label);
564 void branchTestBoolean(Condition cond, const BaseIndex &src, Label *label);
566 void branch32(Condition cond, Register lhs, Register rhs, Label *label) {
567 ma_b(lhs, rhs, label, cond);
568 }
569 void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) {
570 ma_b(lhs, imm, label, cond);
571 }
572 void branch32(Condition cond, const Operand &lhs, Register rhs, Label *label) {
573 if (lhs.getTag() == Operand::REG) {
574 ma_b(lhs.toReg(), rhs, label, cond);
575 } else {
576 branch32(cond, lhs.toAddress(), rhs, label);
577 }
578 }
579 void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) {
580 if (lhs.getTag() == Operand::REG) {
581 ma_b(lhs.toReg(), rhs, label, cond);
582 } else {
583 branch32(cond, lhs.toAddress(), rhs, label);
584 }
585 }
586 void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) {
587 ma_lw(ScratchRegister, lhs);
588 ma_b(ScratchRegister, rhs, label, cond);
589 }
590 void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) {
591 ma_lw(SecondScratchReg, lhs);
592 ma_b(SecondScratchReg, rhs, label, cond);
593 }
594 void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) {
595 branch32(cond, lhs, rhs, label);
596 }
598 void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) {
599 branchPtr(cond, lhs, ptr, label);
600 }
602 void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) {
603 branchPtr(cond, lhs, ptr, label);
604 }
606 void branchPrivatePtr(Condition cond, Register lhs, ImmWord ptr, Label *label) {
607 branchPtr(cond, lhs, ptr, label);
608 }
610 void branchTestDouble(Condition cond, const ValueOperand &value, Label *label);
611 void branchTestDouble(Condition cond, const Register &tag, Label *label);
612 void branchTestDouble(Condition cond, const Address &address, Label *label);
613 void branchTestDouble(Condition cond, const BaseIndex &src, Label *label);
615 void branchTestNull(Condition cond, const ValueOperand &value, Label *label);
616 void branchTestNull(Condition cond, const Register &tag, Label *label);
617 void branchTestNull(Condition cond, const BaseIndex &src, Label *label);
619 void branchTestObject(Condition cond, const ValueOperand &value, Label *label);
620 void branchTestObject(Condition cond, const Register &tag, Label *label);
621 void branchTestObject(Condition cond, const BaseIndex &src, Label *label);
623 void branchTestString(Condition cond, const ValueOperand &value, Label *label);
624 void branchTestString(Condition cond, const Register &tag, Label *label);
625 void branchTestString(Condition cond, const BaseIndex &src, Label *label);
627 void branchTestUndefined(Condition cond, const ValueOperand &value, Label *label);
628 void branchTestUndefined(Condition cond, const Register &tag, Label *label);
629 void branchTestUndefined(Condition cond, const BaseIndex &src, Label *label);
630 void branchTestUndefined(Condition cond, const Address &address, Label *label);
632 void branchTestNumber(Condition cond, const ValueOperand &value, Label *label);
633 void branchTestNumber(Condition cond, const Register &tag, Label *label);
635 void branchTestMagic(Condition cond, const ValueOperand &value, Label *label);
636 void branchTestMagic(Condition cond, const Register &tag, Label *label);
637 void branchTestMagic(Condition cond, const Address &address, Label *label);
638 void branchTestMagic(Condition cond, const BaseIndex &src, Label *label);
640 void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why,
641 Label *label) {
642 MOZ_ASSERT(cond == Equal || cond == NotEqual);
643 // Test for magic
644 Label notmagic;
645 branchTestMagic(cond, val, ¬magic);
646 // Test magic value
647 branch32(cond, val.payloadReg(), Imm32(static_cast<int32_t>(why)), label);
648 bind(¬magic);
649 }
651 void branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label);
653 void branchTestStringTruthy(bool b, const ValueOperand &value, Label *label);
655 void branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label);
657 void branchTestBooleanTruthy(bool b, const ValueOperand &operand, Label *label);
659 void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
660 MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned);
661 if (lhs == rhs) {
662 ma_b(lhs, rhs, label, cond);
663 } else {
664 as_and(ScratchRegister, lhs, rhs);
665 ma_b(ScratchRegister, ScratchRegister, label, cond);
666 }
667 }
668 void branchTest32(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
669 ma_li(ScratchRegister, imm);
670 branchTest32(cond, lhs, ScratchRegister, label);
671 }
672 void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) {
673 ma_lw(SecondScratchReg, address);
674 branchTest32(cond, SecondScratchReg, imm, label);
675 }
676 void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) {
677 branchTest32(cond, lhs, rhs, label);
678 }
679 void branchTestPtr(Condition cond, const Register &lhs, const Imm32 rhs, Label *label) {
680 branchTest32(cond, lhs, rhs, label);
681 }
682 void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) {
683 branchTest32(cond, lhs, imm, label);
684 }
685 void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) {
686 ma_b(lhs, rhs, label, cond);
687 }
688 void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label *label) {
689 ma_li(ScratchRegister, ptr);
690 ma_b(lhs, ScratchRegister, label, cond);
691 }
692 void branchPtr(Condition cond, Register lhs, ImmWord imm, Label *label) {
693 ma_b(lhs, Imm32(imm.value), label, cond);
694 }
695 void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label *label) {
696 branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label);
697 }
698 void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label *label) {
699 movePtr(imm, ScratchRegister);
700 branchPtr(cond, lhs, ScratchRegister, label);
701 }
702 void branchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) {
703 ma_b(lhs, imm, label, cond);
704 }
705 void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) {
706 subPtr(imm, lhs);
707 branch32(cond, lhs, Imm32(0), label);
708 }
710 protected:
711 uint32_t getType(const Value &val);
712 void moveData(const Value &val, Register data);
713 public:
714 void moveValue(const Value &val, Register type, Register data);
716 CodeOffsetJump jumpWithPatch(RepatchLabel *label);
718 template <typename T>
719 CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel *label) {
720 movePtr(ptr, ScratchRegister);
721 Label skipJump;
722 ma_b(reg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump);
723 CodeOffsetJump off = jumpWithPatch(label);
724 bind(&skipJump);
725 return off;
726 }
728 template <typename T>
729 CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel *label) {
730 loadPtr(addr, SecondScratchReg);
731 movePtr(ptr, ScratchRegister);
732 Label skipJump;
733 ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump);
734 CodeOffsetJump off = jumpWithPatch(label);
735 bind(&skipJump);
736 return off;
737 }
738 void branchPtr(Condition cond, Address addr, ImmGCPtr ptr, Label *label) {
739 ma_lw(SecondScratchReg, addr);
740 ma_li(ScratchRegister, ptr);
741 ma_b(SecondScratchReg, ScratchRegister, label, cond);
742 }
743 void branchPtr(Condition cond, Address addr, ImmWord ptr, Label *label) {
744 ma_lw(SecondScratchReg, addr);
745 ma_b(SecondScratchReg, Imm32(ptr.value), label, cond);
746 }
747 void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label *label) {
748 branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label);
749 }
750 void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) {
751 loadPtr(addr, ScratchRegister);
752 ma_b(ScratchRegister, ptr, label, cond);
753 }
754 void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr,
755 Label *label) {
756 loadPtr(addr, ScratchRegister);
757 ma_b(ScratchRegister, ptr, label, cond);
758 }
759 void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) {
760 loadPtr(lhs, SecondScratchReg); // ma_b might use scratch
761 ma_b(SecondScratchReg, rhs, label, cond);
762 }
763 void branch32(Condition cond, const AbsoluteAddress &lhs, const Register &rhs, Label *label) {
764 loadPtr(lhs, ScratchRegister);
765 ma_b(ScratchRegister, rhs, label, cond);
766 }
768 void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) {
769 if (dest.isFloat())
770 loadInt32OrDouble(address, dest.fpu());
771 else
772 ma_lw(dest.gpr(), address);
773 }
775 void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) {
776 if (dest.isFloat())
777 loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale);
778 else
779 load32(address, dest.gpr());
780 }
782 void moveValue(const Value &val, const ValueOperand &dest);
784 void moveValue(const ValueOperand &src, const ValueOperand &dest) {
785 MOZ_ASSERT(src.typeReg() != dest.payloadReg());
786 MOZ_ASSERT(src.payloadReg() != dest.typeReg());
787 if (src.typeReg() != dest.typeReg())
788 ma_move(dest.typeReg(), src.typeReg());
789 if (src.payloadReg() != dest.payloadReg())
790 ma_move(dest.payloadReg(), src.payloadReg());
791 }
793 void storeValue(ValueOperand val, Operand dst);
794 void storeValue(ValueOperand val, const BaseIndex &dest);
795 void storeValue(JSValueType type, Register reg, BaseIndex dest);
796 void storeValue(ValueOperand val, const Address &dest);
797 void storeValue(JSValueType type, Register reg, Address dest);
798 void storeValue(const Value &val, Address dest);
799 void storeValue(const Value &val, BaseIndex dest);
801 void loadValue(Address src, ValueOperand val);
802 void loadValue(Operand dest, ValueOperand val) {
803 loadValue(dest.toAddress(), val);
804 }
805 void loadValue(const BaseIndex &addr, ValueOperand val);
806 void tagValue(JSValueType type, Register payload, ValueOperand dest);
808 void pushValue(ValueOperand val);
809 void popValue(ValueOperand val);
810 void pushValue(const Value &val) {
811 jsval_layout jv = JSVAL_TO_IMPL(val);
812 push(Imm32(jv.s.tag));
813 if (val.isMarkable())
814 push(ImmGCPtr(reinterpret_cast<gc::Cell *>(val.toGCThing())));
815 else
816 push(Imm32(jv.s.payload.i32));
817 }
818 void pushValue(JSValueType type, Register reg) {
819 push(ImmTag(JSVAL_TYPE_TO_TAG(type)));
820 ma_push(reg);
821 }
822 void pushValue(const Address &addr);
823 void Push(const ValueOperand &val) {
824 pushValue(val);
825 framePushed_ += sizeof(Value);
826 }
827 void Pop(const ValueOperand &val) {
828 popValue(val);
829 framePushed_ -= sizeof(Value);
830 }
831 void storePayload(const Value &val, Address dest);
832 void storePayload(Register src, Address dest);
833 void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift);
834 void storePayload(Register src, Register base, Register index, int32_t shift = defaultShift);
835 void storeTypeTag(ImmTag tag, Address dest);
836 void storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift = defaultShift);
838 void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
839 ma_sll(frameSizeReg, frameSizeReg, Imm32(FRAMESIZE_SHIFT));
840 ma_or(frameSizeReg, frameSizeReg, Imm32(type));
841 }
843 void linkExitFrame();
844 void linkParallelExitFrame(const Register &pt);
845 void handleFailureWithHandler(void *handler);
846 void handleFailureWithHandlerTail();
848 /////////////////////////////////////////////////////////////////
849 // Common interface.
850 /////////////////////////////////////////////////////////////////
851 public:
852 // The following functions are exposed for use in platform-shared code.
853 void Push(const Register ®) {
854 ma_push(reg);
855 adjustFrame(sizeof(intptr_t));
856 }
857 void Push(const Imm32 imm) {
858 ma_li(ScratchRegister, imm);
859 ma_push(ScratchRegister);
860 adjustFrame(sizeof(intptr_t));
861 }
862 void Push(const ImmWord imm) {
863 ma_li(ScratchRegister, Imm32(imm.value));
864 ma_push(ScratchRegister);
865 adjustFrame(sizeof(intptr_t));
866 }
867 void Push(const ImmPtr imm) {
868 Push(ImmWord(uintptr_t(imm.value)));
869 }
870 void Push(const ImmGCPtr ptr) {
871 ma_li(ScratchRegister, ptr);
872 ma_push(ScratchRegister);
873 adjustFrame(sizeof(intptr_t));
874 }
875 void Push(const FloatRegister &f) {
876 ma_push(f);
877 adjustFrame(sizeof(double));
878 }
880 CodeOffsetLabel PushWithPatch(const ImmWord &word) {
881 framePushed_ += sizeof(word.value);
882 return pushWithPatch(word);
883 }
884 CodeOffsetLabel PushWithPatch(const ImmPtr &imm) {
885 return PushWithPatch(ImmWord(uintptr_t(imm.value)));
886 }
888 void Pop(const Register ®) {
889 ma_pop(reg);
890 adjustFrame(-sizeof(intptr_t));
891 }
892 void implicitPop(uint32_t args) {
893 MOZ_ASSERT(args % sizeof(intptr_t) == 0);
894 adjustFrame(-args);
895 }
896 uint32_t framePushed() const {
897 return framePushed_;
898 }
899 void setFramePushed(uint32_t framePushed) {
900 framePushed_ = framePushed;
901 }
903 // Builds an exit frame on the stack, with a return address to an internal
904 // non-function. Returns offset to be passed to markSafepointAt().
905 bool buildFakeExitFrame(const Register &scratch, uint32_t *offset);
907 void callWithExitFrame(JitCode *target);
908 void callWithExitFrame(JitCode *target, Register dynStack);
910 // Makes an Ion call using the only two methods that it is sane for
911 // indep code to make a call
912 void callIon(const Register &callee);
914 void reserveStack(uint32_t amount);
915 void freeStack(uint32_t amount);
916 void freeStack(Register amount);
918 void add32(Register src, Register dest);
919 void add32(Imm32 imm, Register dest);
920 void add32(Imm32 imm, const Address &dest);
921 void sub32(Imm32 imm, Register dest);
922 void sub32(Register src, Register dest);
924 void and32(Imm32 imm, Register dest);
925 void and32(Imm32 imm, const Address &dest);
926 void or32(Imm32 imm, const Address &dest);
927 void xor32(Imm32 imm, Register dest);
928 void xorPtr(Imm32 imm, Register dest);
929 void xorPtr(Register src, Register dest);
930 void orPtr(Imm32 imm, Register dest);
931 void orPtr(Register src, Register dest);
932 void andPtr(Imm32 imm, Register dest);
933 void andPtr(Register src, Register dest);
934 void addPtr(Register src, Register dest);
935 void subPtr(Register src, Register dest);
936 void addPtr(const Address &src, Register dest);
937 void not32(Register reg);
939 void move32(const Imm32 &imm, const Register &dest);
940 void move32(const Register &src, const Register &dest);
942 void movePtr(const Register &src, const Register &dest);
943 void movePtr(const ImmWord &imm, const Register &dest);
944 void movePtr(const ImmPtr &imm, const Register &dest);
945 void movePtr(const AsmJSImmPtr &imm, const Register &dest);
946 void movePtr(const ImmGCPtr &imm, const Register &dest);
948 void load8SignExtend(const Address &address, const Register &dest);
949 void load8SignExtend(const BaseIndex &src, const Register &dest);
951 void load8ZeroExtend(const Address &address, const Register &dest);
952 void load8ZeroExtend(const BaseIndex &src, const Register &dest);
954 void load16SignExtend(const Address &address, const Register &dest);
955 void load16SignExtend(const BaseIndex &src, const Register &dest);
957 void load16ZeroExtend(const Address &address, const Register &dest);
958 void load16ZeroExtend(const BaseIndex &src, const Register &dest);
960 void load32(const Address &address, const Register &dest);
961 void load32(const BaseIndex &address, const Register &dest);
962 void load32(const AbsoluteAddress &address, const Register &dest);
964 void loadPtr(const Address &address, const Register &dest);
965 void loadPtr(const BaseIndex &src, const Register &dest);
966 void loadPtr(const AbsoluteAddress &address, const Register &dest);
967 void loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest);
969 void loadPrivate(const Address &address, const Register &dest);
971 void loadDouble(const Address &addr, const FloatRegister &dest);
972 void loadDouble(const BaseIndex &src, const FloatRegister &dest);
974 // Load a float value into a register, then expand it to a double.
975 void loadFloatAsDouble(const Address &addr, const FloatRegister &dest);
976 void loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest);
978 void loadFloat32(const Address &addr, const FloatRegister &dest);
979 void loadFloat32(const BaseIndex &src, const FloatRegister &dest);
981 void store8(const Register &src, const Address &address);
982 void store8(const Imm32 &imm, const Address &address);
983 void store8(const Register &src, const BaseIndex &address);
984 void store8(const Imm32 &imm, const BaseIndex &address);
986 void store16(const Register &src, const Address &address);
987 void store16(const Imm32 &imm, const Address &address);
988 void store16(const Register &src, const BaseIndex &address);
989 void store16(const Imm32 &imm, const BaseIndex &address);
991 void store32(const Register &src, const AbsoluteAddress &address);
992 void store32(const Register &src, const Address &address);
993 void store32(const Register &src, const BaseIndex &address);
994 void store32(const Imm32 &src, const Address &address);
995 void store32(const Imm32 &src, const BaseIndex &address);
997 void storePtr(ImmWord imm, const Address &address);
998 void storePtr(ImmPtr imm, const Address &address);
999 void storePtr(ImmGCPtr imm, const Address &address);
1000 void storePtr(Register src, const Address &address);
1001 void storePtr(const Register &src, const AbsoluteAddress &dest);
1002 void storeDouble(FloatRegister src, Address addr) {
1003 ma_sd(src, addr);
1004 }
1005 void storeDouble(FloatRegister src, BaseIndex addr) {
1006 MOZ_ASSERT(addr.offset == 0);
1007 ma_sd(src, addr);
1008 }
1009 void moveDouble(FloatRegister src, FloatRegister dest) {
1010 as_movd(dest, src);
1011 }
1013 void storeFloat32(FloatRegister src, Address addr) {
1014 ma_ss(src, addr);
1015 }
1016 void storeFloat32(FloatRegister src, BaseIndex addr) {
1017 MOZ_ASSERT(addr.offset == 0);
1018 ma_ss(src, addr);
1019 }
1021 void zeroDouble(FloatRegister reg) {
1022 moveToDoubleLo(zero, reg);
1023 moveToDoubleHi(zero, reg);
1024 }
1026 void clampIntToUint8(Register reg) {
1027 // look at (reg >> 8) if it is 0, then src shouldn't be clamped
1028 // if it is <0, then we want to clamp to 0,
1029 // otherwise, we wish to clamp to 255
1030 Label done;
1031 ma_move(ScratchRegister, reg);
1032 as_sra(ScratchRegister, ScratchRegister, 8);
1033 ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump);
1034 {
1035 Label negative;
1036 ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump);
1037 {
1038 ma_li(reg, Imm32(255));
1039 ma_b(&done, ShortJump);
1040 }
1041 bind(&negative);
1042 {
1043 ma_move(reg, zero);
1044 }
1045 }
1046 bind(&done);
1047 }
1049 void subPtr(Imm32 imm, const Register dest);
1050 void addPtr(Imm32 imm, const Register dest);
1051 void addPtr(Imm32 imm, const Address &dest);
1052 void addPtr(ImmWord imm, const Register dest) {
1053 addPtr(Imm32(imm.value), dest);
1054 }
1055 void addPtr(ImmPtr imm, const Register dest) {
1056 addPtr(ImmWord(uintptr_t(imm.value)), dest);
1057 }
1059 void breakpoint();
1061 void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
1062 Label *label);
1064 void branchFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
1065 Label *label);
1067 void checkStackAlignment();
1069 void alignPointerUp(Register src, Register dest, uint32_t alignment);
1071 void rshiftPtr(Imm32 imm, Register dest) {
1072 ma_srl(dest, dest, imm);
1073 }
1074 void lshiftPtr(Imm32 imm, Register dest) {
1075 ma_sll(dest, dest, imm);
1076 }
1078 // If source is a double, load it into dest. If source is int32,
1079 // convert it to double. Else, branch to failure.
1080 void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure);
1082 // Setup a call to C/C++ code, given the number of general arguments it
1083 // takes. Note that this only supports cdecl.
1084 //
1085 // In order for alignment to work correctly, the MacroAssembler must have a
1086 // consistent view of the stack displacement. It is okay to call "push"
1087 // manually, however, if the stack alignment were to change, the macro
1088 // assembler should be notified before starting a call.
1089 void setupAlignedABICall(uint32_t args);
1091 // Sets up an ABI call for when the alignment is not known. This may need a
1092 // scratch register.
1093 void setupUnalignedABICall(uint32_t args, const Register &scratch);
1095 // Arguments must be assigned in a left-to-right order. This process may
1096 // temporarily use more stack, in which case sp-relative addresses will be
1097 // automatically adjusted. It is extremely important that sp-relative
1098 // addresses are computed *after* setupABICall(). Furthermore, no
1099 // operations should be emitted while setting arguments.
1100 void passABIArg(const MoveOperand &from, MoveOp::Type type);
1101 void passABIArg(const Register ®);
1102 void passABIArg(const FloatRegister ®, MoveOp::Type type);
1103 void passABIArg(const ValueOperand ®s);
1105 protected:
1106 bool buildOOLFakeExitFrame(void *fakeReturnAddr);
1108 private:
1109 void callWithABIPre(uint32_t *stackAdjust);
1110 void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
1112 public:
1113 // Emits a call to a C/C++ function, resolving all argument moves.
1114 void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL);
1115 void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
1116 void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL);
1118 CodeOffsetLabel labelForPatch() {
1119 return CodeOffsetLabel(nextOffset().getOffset());
1120 }
1122 void memIntToValue(Address Source, Address Dest) {
1123 MOZ_ASSUME_UNREACHABLE("NYI");
1124 }
1126 void lea(Operand addr, Register dest) {
1127 MOZ_ASSUME_UNREACHABLE("NYI");
1128 }
1130 void abiret() {
1131 MOZ_ASSUME_UNREACHABLE("NYI");
1132 }
1134 void ma_storeImm(Imm32 imm, const Address &addr) {
1135 ma_sw(imm, addr);
1136 }
1138 BufferOffset ma_BoundsCheck(Register bounded) {
1139 BufferOffset bo = m_buffer.nextOffset();
1140 ma_liPatchable(bounded, Imm32(0));
1141 return bo;
1142 }
1144 void moveFloat32(FloatRegister src, FloatRegister dest) {
1145 as_movs(dest, src);
1146 }
1148 void branchPtrInNurseryRange(Register ptr, Register temp, Label *label);
1149 };
1151 typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific;
1153 } // namespace jit
1154 } // namespace js
1156 #endif /* jit_mips_MacroAssembler_mips_h */