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 // Copyright 2011 the V8 project authors. All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following
12 // disclaimer in the documentation and/or other materials provided
13 // with the distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "jit/mips64/Simulator-mips64.h"
31
32 #include "mozilla/Casting.h"
33 #include "mozilla/FloatingPoint.h"
34 #include "mozilla/Likely.h"
35 #include "mozilla/MathAlgorithms.h"
36
37 #include <float.h>
38
39 #include "asmjs/AsmJSValidate.h"
40 #include "jit/mips64/Assembler-mips64.h"
41 #include "vm/Runtime.h"
42
43 #define I8(v) static_cast<int8_t>(v)
44 #define I16(v) static_cast<int16_t>(v)
45 #define U16(v) static_cast<uint16_t>(v)
46 #define I32(v) static_cast<int32_t>(v)
47 #define U32(v) static_cast<uint32_t>(v)
48 #define I64(v) static_cast<int64_t>(v)
49 #define U64(v) static_cast<uint64_t>(v)
50 #define I128(v) static_cast<__int128_t>(v)
51 #define U128(v) static_cast<unsigned __int128_t>(v)
52
53 namespace js {
54 namespace jit {
55
56 static const Instr kCallRedirInstr = op_special | MAX_BREAK_CODE << FunctionBits | ff_break;
57
58 // Utils functions.
59 static uint32_t
GetFCSRConditionBit(uint32_t cc)60 GetFCSRConditionBit(uint32_t cc)
61 {
62 if (cc == 0)
63 return 23;
64 return 24 + cc;
65 }
66
67 // -----------------------------------------------------------------------------
68 // MIPS assembly various constants.
69
70 class SimInstruction
71 {
72 public:
73 enum {
74 kInstrSize = 4,
75 // On MIPS PC cannot actually be directly accessed. We behave as if PC was
76 // always the value of the current instruction being executed.
77 kPCReadOffset = 0
78 };
79
80 // Get the raw instruction bits.
instructionBits() const81 inline Instr instructionBits() const {
82 return *reinterpret_cast<const Instr*>(this);
83 }
84
85 // Set the raw instruction bits to value.
setInstructionBits(Instr value)86 inline void setInstructionBits(Instr value) {
87 *reinterpret_cast<Instr*>(this) = value;
88 }
89
90 // Read one particular bit out of the instruction bits.
bit(int nr) const91 inline int bit(int nr) const {
92 return (instructionBits() >> nr) & 1;
93 }
94
95 // Read a bit field out of the instruction bits.
bits(int hi,int lo) const96 inline int bits(int hi, int lo) const {
97 return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
98 }
99
100 // Instruction type.
101 enum Type {
102 kRegisterType,
103 kImmediateType,
104 kJumpType,
105 kUnsupported = -1
106 };
107
108 // Get the encoding type of the instruction.
109 Type instructionType() const;
110
111
112 // Accessors for the different named fields used in the MIPS encoding.
opcodeValue() const113 inline Opcode opcodeValue() const {
114 return static_cast<Opcode>(bits(OpcodeShift + OpcodeBits - 1, OpcodeShift));
115 }
116
rsValue() const117 inline int rsValue() const {
118 MOZ_ASSERT(instructionType() == kRegisterType || instructionType() == kImmediateType);
119 return bits(RSShift + RSBits - 1, RSShift);
120 }
121
rtValue() const122 inline int rtValue() const {
123 MOZ_ASSERT(instructionType() == kRegisterType || instructionType() == kImmediateType);
124 return bits(RTShift + RTBits - 1, RTShift);
125 }
126
rdValue() const127 inline int rdValue() const {
128 MOZ_ASSERT(instructionType() == kRegisterType);
129 return bits(RDShift + RDBits - 1, RDShift);
130 }
131
saValue() const132 inline int saValue() const {
133 MOZ_ASSERT(instructionType() == kRegisterType);
134 return bits(SAShift + SABits - 1, SAShift);
135 }
136
functionValue() const137 inline int functionValue() const {
138 MOZ_ASSERT(instructionType() == kRegisterType || instructionType() == kImmediateType);
139 return bits(FunctionShift + FunctionBits - 1, FunctionShift);
140 }
141
fdValue() const142 inline int fdValue() const {
143 return bits(FDShift + FDBits - 1, FDShift);
144 }
145
fsValue() const146 inline int fsValue() const {
147 return bits(FSShift + FSBits - 1, FSShift);
148 }
149
ftValue() const150 inline int ftValue() const {
151 return bits(FTShift + FTBits - 1, FTShift);
152 }
153
frValue() const154 inline int frValue() const {
155 return bits(FRShift + FRBits - 1, FRShift);
156 }
157
158 // Float Compare condition code instruction bits.
fcccValue() const159 inline int fcccValue() const {
160 return bits(FCccShift + FCccBits - 1, FCccShift);
161 }
162
163 // Float Branch condition code instruction bits.
fbccValue() const164 inline int fbccValue() const {
165 return bits(FBccShift + FBccBits - 1, FBccShift);
166 }
167
168 // Float Branch true/false instruction bit.
fbtrueValue() const169 inline int fbtrueValue() const {
170 return bits(FBtrueShift + FBtrueBits - 1, FBtrueShift);
171 }
172
173 // Return the fields at their original place in the instruction encoding.
opcodeFieldRaw() const174 inline Opcode opcodeFieldRaw() const {
175 return static_cast<Opcode>(instructionBits() & OpcodeMask);
176 }
177
rsFieldRaw() const178 inline int rsFieldRaw() const {
179 MOZ_ASSERT(instructionType() == kRegisterType || instructionType() == kImmediateType);
180 return instructionBits() & RSMask;
181 }
182
183 // Same as above function, but safe to call within instructionType().
rsFieldRawNoAssert() const184 inline int rsFieldRawNoAssert() const {
185 return instructionBits() & RSMask;
186 }
187
rtFieldRaw() const188 inline int rtFieldRaw() const {
189 MOZ_ASSERT(instructionType() == kRegisterType || instructionType() == kImmediateType);
190 return instructionBits() & RTMask;
191 }
192
rdFieldRaw() const193 inline int rdFieldRaw() const {
194 MOZ_ASSERT(instructionType() == kRegisterType);
195 return instructionBits() & RDMask;
196 }
197
saFieldRaw() const198 inline int saFieldRaw() const {
199 MOZ_ASSERT(instructionType() == kRegisterType);
200 return instructionBits() & SAMask;
201 }
202
functionFieldRaw() const203 inline int functionFieldRaw() const {
204 return instructionBits() & FunctionMask;
205 }
206
207 // Get the secondary field according to the opcode.
secondaryValue() const208 inline int secondaryValue() const {
209 Opcode op = opcodeFieldRaw();
210 switch (op) {
211 case op_special:
212 case op_special2:
213 return functionValue();
214 case op_cop1:
215 return rsValue();
216 case op_regimm:
217 return rtValue();
218 default:
219 return ff_null;
220 }
221 }
222
imm16Value() const223 inline int32_t imm16Value() const {
224 MOZ_ASSERT(instructionType() == kImmediateType);
225 return bits(Imm16Shift + Imm16Bits - 1, Imm16Shift);
226 }
227
imm26Value() const228 inline int32_t imm26Value() const {
229 MOZ_ASSERT(instructionType() == kJumpType);
230 return bits(Imm26Shift + Imm26Bits - 1, Imm26Shift);
231 }
232
233 // Say if the instruction should not be used in a branch delay slot.
234 bool isForbiddenInBranchDelay() const;
235 // Say if the instruction 'links'. e.g. jal, bal.
236 bool isLinkingInstruction() const;
237 // Say if the instruction is a break or a trap.
238 bool isTrap() const;
239
240 private:
241
242 SimInstruction() = delete;
243 SimInstruction(const SimInstruction& other) = delete;
244 void operator=(const SimInstruction& other) = delete;
245 };
246
247 bool
isForbiddenInBranchDelay() const248 SimInstruction::isForbiddenInBranchDelay() const
249 {
250 const int op = opcodeFieldRaw();
251 switch (op) {
252 case op_j:
253 case op_jal:
254 case op_beq:
255 case op_bne:
256 case op_blez:
257 case op_bgtz:
258 case op_beql:
259 case op_bnel:
260 case op_blezl:
261 case op_bgtzl:
262 return true;
263 case op_regimm:
264 switch (rtFieldRaw()) {
265 case rt_bltz:
266 case rt_bgez:
267 case rt_bltzal:
268 case rt_bgezal:
269 return true;
270 default:
271 return false;
272 };
273 break;
274 case op_special:
275 switch (functionFieldRaw()) {
276 case ff_jr:
277 case ff_jalr:
278 return true;
279 default:
280 return false;
281 };
282 break;
283 default:
284 return false;
285 };
286 }
287
288 bool
isLinkingInstruction() const289 SimInstruction::isLinkingInstruction() const
290 {
291 const int op = opcodeFieldRaw();
292 switch (op) {
293 case op_jal:
294 return true;
295 case op_regimm:
296 switch (rtFieldRaw()) {
297 case rt_bgezal:
298 case rt_bltzal:
299 return true;
300 default:
301 return false;
302 };
303 case op_special:
304 switch (functionFieldRaw()) {
305 case ff_jalr:
306 return true;
307 default:
308 return false;
309 };
310 default:
311 return false;
312 };
313 }
314
315 bool
isTrap() const316 SimInstruction::isTrap() const
317 {
318 if (opcodeFieldRaw() != op_special) {
319 return false;
320 } else {
321 switch (functionFieldRaw()) {
322 case ff_break:
323 case ff_tge:
324 case ff_tgeu:
325 case ff_tlt:
326 case ff_tltu:
327 case ff_teq:
328 case ff_tne:
329 return true;
330 default:
331 return false;
332 };
333 }
334 }
335
336 SimInstruction::Type
instructionType() const337 SimInstruction::instructionType() const
338 {
339 switch (opcodeFieldRaw()) {
340 case op_special:
341 switch (functionFieldRaw()) {
342 case ff_jr:
343 case ff_jalr:
344 case ff_sync:
345 case ff_break:
346 case ff_sll:
347 case ff_dsll:
348 case ff_dsll32:
349 case ff_srl:
350 case ff_dsrl:
351 case ff_dsrl32:
352 case ff_sra:
353 case ff_dsra:
354 case ff_dsra32:
355 case ff_sllv:
356 case ff_dsllv:
357 case ff_srlv:
358 case ff_dsrlv:
359 case ff_srav:
360 case ff_dsrav:
361 case ff_mfhi:
362 case ff_mflo:
363 case ff_mult:
364 case ff_dmult:
365 case ff_multu:
366 case ff_dmultu:
367 case ff_div:
368 case ff_ddiv:
369 case ff_divu:
370 case ff_ddivu:
371 case ff_add:
372 case ff_dadd:
373 case ff_addu:
374 case ff_daddu:
375 case ff_sub:
376 case ff_dsub:
377 case ff_subu:
378 case ff_dsubu:
379 case ff_and:
380 case ff_or:
381 case ff_xor:
382 case ff_nor:
383 case ff_slt:
384 case ff_sltu:
385 case ff_tge:
386 case ff_tgeu:
387 case ff_tlt:
388 case ff_tltu:
389 case ff_teq:
390 case ff_tne:
391 case ff_movz:
392 case ff_movn:
393 case ff_movci:
394 return kRegisterType;
395 default:
396 return kUnsupported;
397 };
398 break;
399 case op_special2:
400 switch (functionFieldRaw()) {
401 case ff_mul:
402 case ff_clz:
403 case ff_dclz:
404 return kRegisterType;
405 default:
406 return kUnsupported;
407 };
408 break;
409 case op_special3:
410 switch (functionFieldRaw()) {
411 case ff_ins:
412 case ff_dins:
413 case ff_dinsm:
414 case ff_dinsu:
415 case ff_ext:
416 case ff_dext:
417 case ff_dextm:
418 case ff_dextu:
419 case ff_bshfl:
420 return kRegisterType;
421 default:
422 return kUnsupported;
423 };
424 break;
425 case op_cop1: // Coprocessor instructions.
426 switch (rsFieldRawNoAssert()) {
427 case rs_bc1: // Branch on coprocessor condition.
428 return kImmediateType;
429 default:
430 return kRegisterType;
431 };
432 break;
433 case op_cop1x:
434 return kRegisterType;
435 // 16 bits Immediate type instructions. e.g.: addi dest, src, imm16.
436 case op_regimm:
437 case op_beq:
438 case op_bne:
439 case op_blez:
440 case op_bgtz:
441 case op_addi:
442 case op_daddi:
443 case op_addiu:
444 case op_daddiu:
445 case op_slti:
446 case op_sltiu:
447 case op_andi:
448 case op_ori:
449 case op_xori:
450 case op_lui:
451 case op_beql:
452 case op_bnel:
453 case op_blezl:
454 case op_bgtzl:
455 case op_lb:
456 case op_lbu:
457 case op_lh:
458 case op_lhu:
459 case op_lw:
460 case op_lwu:
461 case op_lwl:
462 case op_lwr:
463 case op_ll:
464 case op_ld:
465 case op_ldl:
466 case op_ldr:
467 case op_sb:
468 case op_sh:
469 case op_sw:
470 case op_swl:
471 case op_swr:
472 case op_sc:
473 case op_sd:
474 case op_sdl:
475 case op_sdr:
476 case op_lwc1:
477 case op_ldc1:
478 case op_swc1:
479 case op_sdc1:
480 return kImmediateType;
481 // 26 bits immediate type instructions. e.g.: j imm26.
482 case op_j:
483 case op_jal:
484 return kJumpType;
485 default:
486 return kUnsupported;
487 };
488 return kUnsupported;
489 }
490
491 // C/C++ argument slots size.
492 const int kCArgSlotCount = 0;
493 const int kCArgsSlotsSize = kCArgSlotCount * sizeof(uintptr_t);
494 const int kBranchReturnOffset = 2 * SimInstruction::kInstrSize;
495
496 class CachePage {
497 public:
498 static const int LINE_VALID = 0;
499 static const int LINE_INVALID = 1;
500
501 static const int kPageShift = 12;
502 static const int kPageSize = 1 << kPageShift;
503 static const int kPageMask = kPageSize - 1;
504 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
505 static const int kLineLength = 1 << kLineShift;
506 static const int kLineMask = kLineLength - 1;
507
CachePage()508 CachePage() {
509 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
510 }
511
validityByte(int offset)512 char* validityByte(int offset) {
513 return &validity_map_[offset >> kLineShift];
514 }
515
cachedData(int offset)516 char* cachedData(int offset) {
517 return &data_[offset];
518 }
519
520 private:
521 char data_[kPageSize]; // The cached data.
522 static const int kValidityMapSize = kPageSize >> kLineShift;
523 char validity_map_[kValidityMapSize]; // One byte per line.
524 };
525
526 // Protects the icache() and redirection() properties of the
527 // Simulator.
528 class AutoLockSimulatorCache
529 {
530 public:
AutoLockSimulatorCache(Simulator * sim)531 explicit AutoLockSimulatorCache(Simulator* sim) : sim_(sim) {
532 PR_Lock(sim_->cacheLock_);
533 MOZ_ASSERT(!sim_->cacheLockHolder_);
534 #ifdef DEBUG
535 sim_->cacheLockHolder_ = PR_GetCurrentThread();
536 #endif
537 }
538
~AutoLockSimulatorCache()539 ~AutoLockSimulatorCache() {
540 MOZ_ASSERT(sim_->cacheLockHolder_);
541 #ifdef DEBUG
542 sim_->cacheLockHolder_ = nullptr;
543 #endif
544 PR_Unlock(sim_->cacheLock_);
545 }
546
547 private:
548 Simulator* const sim_;
549 };
550
551 bool Simulator::ICacheCheckingEnabled = false;
552
553 int64_t Simulator::StopSimAt = -1;
554
555 Simulator *
Create()556 Simulator::Create()
557 {
558 Simulator* sim = js_new<Simulator>();
559 if (!sim)
560 return nullptr;
561
562 if (!sim->init()) {
563 js_delete(sim);
564 return nullptr;
565 }
566
567 if (getenv("MIPS_SIM_ICACHE_CHECKS"))
568 Simulator::ICacheCheckingEnabled = true;
569
570 int64_t stopAt;
571 char* stopAtStr = getenv("MIPS_SIM_STOP_AT");
572 if (stopAtStr && sscanf(stopAtStr, "%ld", &stopAt) == 1) {
573 fprintf(stderr, "\nStopping simulation at icount %ld\n", stopAt);
574 Simulator::StopSimAt = stopAt;
575 }
576
577 return sim;
578 }
579
580 void
Destroy(Simulator * sim)581 Simulator::Destroy(Simulator* sim)
582 {
583 js_delete(sim);
584 }
585
586 // The MipsDebugger class is used by the simulator while debugging simulated
587 // code.
588 class MipsDebugger
589 {
590 public:
MipsDebugger(Simulator * sim)591 explicit MipsDebugger(Simulator* sim) : sim_(sim) { }
592
593 void stop(SimInstruction* instr);
594 void debug();
595 // Print all registers with a nice formatting.
596 void printAllRegs();
597 void printAllRegsIncludingFPU();
598
599 private:
600 // We set the breakpoint code to 0xfffff to easily recognize it.
601 static const Instr kBreakpointInstr = op_special | ff_break | 0xfffff << 6;
602 static const Instr kNopInstr = op_special | ff_sll;
603
604 Simulator* sim_;
605
606 int64_t getRegisterValue(int regnum);
607 int64_t getFPURegisterValueLong(int regnum);
608 float getFPURegisterValueFloat(int regnum);
609 double getFPURegisterValueDouble(int regnum);
610 bool getValue(const char* desc, int64_t* value);
611
612 // Set or delete a breakpoint. Returns true if successful.
613 bool setBreakpoint(SimInstruction* breakpc);
614 bool deleteBreakpoint(SimInstruction* breakpc);
615
616 // Undo and redo all breakpoints. This is needed to bracket disassembly and
617 // execution to skip past breakpoints when run from the debugger.
618 void undoBreakpoints();
619 void redoBreakpoints();
620 };
621
622 static void
UNSUPPORTED()623 UNSUPPORTED()
624 {
625 printf("Unsupported instruction.\n");
626 MOZ_CRASH();
627 }
628
629 void
stop(SimInstruction * instr)630 MipsDebugger::stop(SimInstruction* instr)
631 {
632 // Get the stop code.
633 uint32_t code = instr->bits(25, 6);
634 // Retrieve the encoded address, which comes just after this stop.
635 char* msg = *reinterpret_cast<char**>(sim_->get_pc() +
636 SimInstruction::kInstrSize);
637 // Update this stop description.
638 if (!sim_->watchedStops_[code].desc_)
639 sim_->watchedStops_[code].desc_ = msg;
640 // Print the stop message and code if it is not the default code.
641 if (code != kMaxStopCode)
642 printf("Simulator hit stop %u: %s\n", code, msg);
643 else
644 printf("Simulator hit %s\n", msg);
645 sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
646 debug();
647 }
648
649 int64_t
getRegisterValue(int regnum)650 MipsDebugger::getRegisterValue(int regnum)
651 {
652 if (regnum == kPCRegister)
653 return sim_->get_pc();
654 return sim_->getRegister(regnum);
655 }
656
657 int64_t
getFPURegisterValueLong(int regnum)658 MipsDebugger::getFPURegisterValueLong(int regnum)
659 {
660 return sim_->getFpuRegister(regnum);
661 }
662
663 float
getFPURegisterValueFloat(int regnum)664 MipsDebugger::getFPURegisterValueFloat(int regnum)
665 {
666 return sim_->getFpuRegisterFloat(regnum);
667 }
668
669 double
getFPURegisterValueDouble(int regnum)670 MipsDebugger::getFPURegisterValueDouble(int regnum)
671 {
672 return sim_->getFpuRegisterDouble(regnum);
673 }
674
675 bool
getValue(const char * desc,int64_t * value)676 MipsDebugger::getValue(const char* desc, int64_t* value)
677 {
678 Register reg = Register::FromName(desc);
679 if (reg != InvalidReg) {
680 *value = getRegisterValue(reg.code());
681 return true;
682 }
683
684 if (strncmp(desc, "0x", 2) == 0)
685 return sscanf(desc, "%lx", reinterpret_cast<uint64_t*>(value)) == 1;
686 return sscanf(desc, "%li", value) == 1;
687 }
688
689 bool
setBreakpoint(SimInstruction * breakpc)690 MipsDebugger::setBreakpoint(SimInstruction* breakpc)
691 {
692 // Check if a breakpoint can be set. If not return without any side-effects.
693 if (sim_->break_pc_ != nullptr)
694 return false;
695
696 // Set the breakpoint.
697 sim_->break_pc_ = breakpc;
698 sim_->break_instr_ = breakpc->instructionBits();
699 // Not setting the breakpoint instruction in the code itself. It will be set
700 // when the debugger shell continues.
701 return true;
702
703 }
704
705 bool
deleteBreakpoint(SimInstruction * breakpc)706 MipsDebugger::deleteBreakpoint(SimInstruction* breakpc)
707 {
708 if (sim_->break_pc_ != nullptr)
709 sim_->break_pc_->setInstructionBits(sim_->break_instr_);
710
711 sim_->break_pc_ = nullptr;
712 sim_->break_instr_ = 0;
713 return true;
714 }
715
716 void
undoBreakpoints()717 MipsDebugger::undoBreakpoints()
718 {
719 if (sim_->break_pc_)
720 sim_->break_pc_->setInstructionBits(sim_->break_instr_);
721 }
722
723 void
redoBreakpoints()724 MipsDebugger::redoBreakpoints()
725 {
726 if (sim_->break_pc_)
727 sim_->break_pc_->setInstructionBits(kBreakpointInstr);
728 }
729
730 void
printAllRegs()731 MipsDebugger::printAllRegs()
732 {
733 int64_t value;
734 for (uint32_t i = 0; i < Registers::Total; i++) {
735 value = getRegisterValue(i);
736 printf("%3s: 0x%016lx %20ld ", Registers::GetName(i), value, value);
737
738 if (i % 2)
739 printf("\n");
740 }
741 printf("\n");
742
743 value = getRegisterValue(Simulator::LO);
744 printf(" LO: 0x%016lx %20ld ", value, value);
745 value = getRegisterValue(Simulator::HI);
746 printf(" HI: 0x%016lx %20ld\n", value, value);
747 value = getRegisterValue(Simulator::pc);
748 printf(" pc: 0x%016lx\n", value);
749 }
750
751 void
printAllRegsIncludingFPU()752 MipsDebugger::printAllRegsIncludingFPU()
753 {
754 printAllRegs();
755
756 printf("\n\n");
757 // f0, f1, f2, ... f31.
758 for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) {
759 printf("%3s: 0x%016lx\tflt: %-8.4g\tdbl: %-16.4g\n",
760 FloatRegisters::GetName(i),
761 getFPURegisterValueLong(i),
762 getFPURegisterValueFloat(i),
763 getFPURegisterValueDouble(i));
764 }
765 }
766
767 static char*
ReadLine(const char * prompt)768 ReadLine(const char* prompt)
769 {
770 char* result = nullptr;
771 char lineBuf[256];
772 int offset = 0;
773 bool keepGoing = true;
774 fprintf(stdout, "%s", prompt);
775 fflush(stdout);
776 while (keepGoing) {
777 if (fgets(lineBuf, sizeof(lineBuf), stdin) == nullptr) {
778 // fgets got an error. Just give up.
779 if (result)
780 js_delete(result);
781 return nullptr;
782 }
783 int len = strlen(lineBuf);
784 if (len > 0 && lineBuf[len - 1] == '\n') {
785 // Since we read a new line we are done reading the line. This
786 // will exit the loop after copying this buffer into the result.
787 keepGoing = false;
788 }
789 if (!result) {
790 // Allocate the initial result and make room for the terminating '\0'
791 result = (char*)js_malloc(len + 1);
792 if (!result)
793 return nullptr;
794 } else {
795 // Allocate a new result with enough room for the new addition.
796 int new_len = offset + len + 1;
797 char* new_result = (char*)js_malloc(new_len);
798 if (!new_result)
799 return nullptr;
800 // Copy the existing input into the new array and set the new
801 // array as the result.
802 memcpy(new_result, result, offset * sizeof(char));
803 js_free(result);
804 result = new_result;
805 }
806 // Copy the newly read line into the result.
807 memcpy(result + offset, lineBuf, len * sizeof(char));
808 offset += len;
809 }
810
811 MOZ_ASSERT(result);
812 result[offset] = '\0';
813 return result;
814 }
815
816 static void
DisassembleInstruction(uint64_t pc)817 DisassembleInstruction(uint64_t pc)
818 {
819 uint8_t* bytes = reinterpret_cast<uint8_t*>(pc);
820 char hexbytes[256];
821 sprintf(hexbytes, "0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3]);
822 char llvmcmd[1024];
823 sprintf(llvmcmd, "bash -c \"echo -n '%p'; echo '%s' | "
824 "llvm-mc -disassemble -arch=mips64el -mcpu=mips64r2 | "
825 "grep -v pure_instructions | grep -v .text\"", static_cast<void*>(bytes), hexbytes);
826 if (system(llvmcmd))
827 printf("Cannot disassemble instruction.\n");
828 }
829
830 void
debug()831 MipsDebugger::debug()
832 {
833 intptr_t lastPC = -1;
834 bool done = false;
835
836 #define COMMAND_SIZE 63
837 #define ARG_SIZE 255
838
839 #define STR(a) #a
840 #define XSTR(a) STR(a)
841
842 char cmd[COMMAND_SIZE + 1];
843 char arg1[ARG_SIZE + 1];
844 char arg2[ARG_SIZE + 1];
845 char* argv[3] = { cmd, arg1, arg2 };
846
847 // Make sure to have a proper terminating character if reaching the limit.
848 cmd[COMMAND_SIZE] = 0;
849 arg1[ARG_SIZE] = 0;
850 arg2[ARG_SIZE] = 0;
851
852 // Undo all set breakpoints while running in the debugger shell. This will
853 // make them invisible to all commands.
854 undoBreakpoints();
855
856 while (!done && (sim_->get_pc() != Simulator::end_sim_pc)) {
857 if (lastPC != sim_->get_pc()) {
858 DisassembleInstruction(sim_->get_pc());
859 lastPC = sim_->get_pc();
860 }
861 char* line = ReadLine("sim> ");
862 if (line == nullptr) {
863 break;
864 } else {
865 char* last_input = sim_->lastDebuggerInput();
866 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
867 line = last_input;
868 } else {
869 // Ownership is transferred to sim_;
870 sim_->setLastDebuggerInput(line);
871 }
872 // Use sscanf to parse the individual parts of the command line. At the
873 // moment no command expects more than two parameters.
874 int argc = sscanf(line,
875 "%" XSTR(COMMAND_SIZE) "s "
876 "%" XSTR(ARG_SIZE) "s "
877 "%" XSTR(ARG_SIZE) "s",
878 cmd, arg1, arg2);
879 if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
880 SimInstruction* instr = reinterpret_cast<SimInstruction*>(sim_->get_pc());
881 if (!(instr->isTrap()) ||
882 instr->instructionBits() == kCallRedirInstr) {
883 sim_->instructionDecode(
884 reinterpret_cast<SimInstruction*>(sim_->get_pc()));
885 } else {
886 // Allow si to jump over generated breakpoints.
887 printf("/!\\ Jumping over generated breakpoint.\n");
888 sim_->set_pc(sim_->get_pc() + SimInstruction::kInstrSize);
889 }
890 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
891 // Execute the one instruction we broke at with breakpoints disabled.
892 sim_->instructionDecode(reinterpret_cast<SimInstruction*>(sim_->get_pc()));
893 // Leave the debugger shell.
894 done = true;
895 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
896 if (argc == 2) {
897 int64_t value;
898 if (strcmp(arg1, "all") == 0) {
899 printAllRegs();
900 } else if (strcmp(arg1, "allf") == 0) {
901 printAllRegsIncludingFPU();
902 } else {
903 Register reg = Register::FromName(arg1);
904 FloatRegisters::Encoding fReg = FloatRegisters::FromName(arg1);
905 if (reg != InvalidReg) {
906 value = getRegisterValue(reg.code());
907 printf("%s: 0x%016lx %20ld \n", arg1, value, value);
908 } else if (fReg != FloatRegisters::Invalid) {
909 printf("%3s: 0x%016lx\tflt: %-8.4g\tdbl: %-16.4g\n",
910 FloatRegisters::GetName(fReg),
911 getFPURegisterValueLong(fReg),
912 getFPURegisterValueFloat(fReg),
913 getFPURegisterValueDouble(fReg));
914 } else {
915 printf("%s unrecognized\n", arg1);
916 }
917 }
918 } else {
919 printf("print <register> or print <fpu register> single\n");
920 }
921 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
922 int64_t* cur = nullptr;
923 int64_t* end = nullptr;
924 int next_arg = 1;
925
926 if (strcmp(cmd, "stack") == 0) {
927 cur = reinterpret_cast<int64_t*>(sim_->getRegister(Simulator::sp));
928 } else { // Command "mem".
929 int64_t value;
930 if (!getValue(arg1, &value)) {
931 printf("%s unrecognized\n", arg1);
932 continue;
933 }
934 cur = reinterpret_cast<int64_t*>(value);
935 next_arg++;
936 }
937
938 int64_t words;
939 if (argc == next_arg) {
940 words = 10;
941 } else {
942 if (!getValue(argv[next_arg], &words)) {
943 words = 10;
944 }
945 }
946 end = cur + words;
947
948 while (cur < end) {
949 printf(" %p: 0x%016lx %20ld", cur, *cur, *cur);
950 printf("\n");
951 cur++;
952 }
953
954 } else if ((strcmp(cmd, "disasm") == 0) ||
955 (strcmp(cmd, "dpc") == 0) ||
956 (strcmp(cmd, "di") == 0)) {
957 uint8_t* cur = nullptr;
958 uint8_t* end = nullptr;
959
960 if (argc == 1) {
961 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
962 end = cur + (10 * SimInstruction::kInstrSize);
963 } else if (argc == 2) {
964 Register reg = Register::FromName(arg1);
965 if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
966 // The argument is an address or a register name.
967 int64_t value;
968 if (getValue(arg1, &value)) {
969 cur = reinterpret_cast<uint8_t*>(value);
970 // Disassemble 10 instructions at <arg1>.
971 end = cur + (10 * SimInstruction::kInstrSize);
972 }
973 } else {
974 // The argument is the number of instructions.
975 int64_t value;
976 if (getValue(arg1, &value)) {
977 cur = reinterpret_cast<uint8_t*>(sim_->get_pc());
978 // Disassemble <arg1> instructions.
979 end = cur + (value * SimInstruction::kInstrSize);
980 }
981 }
982 } else {
983 int64_t value1;
984 int64_t value2;
985 if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
986 cur = reinterpret_cast<uint8_t*>(value1);
987 end = cur + (value2 * SimInstruction::kInstrSize);
988 }
989 }
990
991 while (cur < end) {
992 DisassembleInstruction(uint64_t(cur));
993 cur += SimInstruction::kInstrSize;
994 }
995 } else if (strcmp(cmd, "gdb") == 0) {
996 printf("relinquishing control to gdb\n");
997 asm("int $3");
998 printf("regaining control from gdb\n");
999 } else if (strcmp(cmd, "break") == 0) {
1000 if (argc == 2) {
1001 int64_t value;
1002 if (getValue(arg1, &value)) {
1003 if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value)))
1004 printf("setting breakpoint failed\n");
1005 } else {
1006 printf("%s unrecognized\n", arg1);
1007 }
1008 } else {
1009 printf("break <address>\n");
1010 }
1011 } else if (strcmp(cmd, "del") == 0) {
1012 if (!deleteBreakpoint(nullptr)) {
1013 printf("deleting breakpoint failed\n");
1014 }
1015 } else if (strcmp(cmd, "flags") == 0) {
1016 printf("No flags on MIPS !\n");
1017 } else if (strcmp(cmd, "stop") == 0) {
1018 int64_t value;
1019 intptr_t stop_pc = sim_->get_pc() -
1020 2 * SimInstruction::kInstrSize;
1021 SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc);
1022 SimInstruction* msg_address =
1023 reinterpret_cast<SimInstruction*>(stop_pc +
1024 SimInstruction::kInstrSize);
1025 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
1026 // Remove the current stop.
1027 if (sim_->isStopInstruction(stop_instr)) {
1028 stop_instr->setInstructionBits(kNopInstr);
1029 msg_address->setInstructionBits(kNopInstr);
1030 } else {
1031 printf("Not at debugger stop.\n");
1032 }
1033 } else if (argc == 3) {
1034 // Print information about all/the specified breakpoint(s).
1035 if (strcmp(arg1, "info") == 0) {
1036 if (strcmp(arg2, "all") == 0) {
1037 printf("Stop information:\n");
1038 for (uint32_t i = kMaxWatchpointCode + 1;
1039 i <= kMaxStopCode;
1040 i++) {
1041 sim_->printStopInfo(i);
1042 }
1043 } else if (getValue(arg2, &value)) {
1044 sim_->printStopInfo(value);
1045 } else {
1046 printf("Unrecognized argument.\n");
1047 }
1048 } else if (strcmp(arg1, "enable") == 0) {
1049 // Enable all/the specified breakpoint(s).
1050 if (strcmp(arg2, "all") == 0) {
1051 for (uint32_t i = kMaxWatchpointCode + 1;
1052 i <= kMaxStopCode;
1053 i++) {
1054 sim_->enableStop(i);
1055 }
1056 } else if (getValue(arg2, &value)) {
1057 sim_->enableStop(value);
1058 } else {
1059 printf("Unrecognized argument.\n");
1060 }
1061 } else if (strcmp(arg1, "disable") == 0) {
1062 // Disable all/the specified breakpoint(s).
1063 if (strcmp(arg2, "all") == 0) {
1064 for (uint32_t i = kMaxWatchpointCode + 1;
1065 i <= kMaxStopCode;
1066 i++) {
1067 sim_->disableStop(i);
1068 }
1069 } else if (getValue(arg2, &value)) {
1070 sim_->disableStop(value);
1071 } else {
1072 printf("Unrecognized argument.\n");
1073 }
1074 }
1075 } else {
1076 printf("Wrong usage. Use help command for more information.\n");
1077 }
1078 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
1079 printf("cont\n");
1080 printf(" continue execution (alias 'c')\n");
1081 printf("stepi\n");
1082 printf(" step one instruction (alias 'si')\n");
1083 printf("print <register>\n");
1084 printf(" print register content (alias 'p')\n");
1085 printf(" use register name 'all' to print all registers\n");
1086 printf("printobject <register>\n");
1087 printf(" print an object from a register (alias 'po')\n");
1088 printf("stack [<words>]\n");
1089 printf(" dump stack content, default dump 10 words)\n");
1090 printf("mem <address> [<words>]\n");
1091 printf(" dump memory content, default dump 10 words)\n");
1092 printf("flags\n");
1093 printf(" print flags\n");
1094 printf("disasm [<instructions>]\n");
1095 printf("disasm [<address/register>]\n");
1096 printf("disasm [[<address/register>] <instructions>]\n");
1097 printf(" disassemble code, default is 10 instructions\n");
1098 printf(" from pc (alias 'di')\n");
1099 printf("gdb\n");
1100 printf(" enter gdb\n");
1101 printf("break <address>\n");
1102 printf(" set a break point on the address\n");
1103 printf("del\n");
1104 printf(" delete the breakpoint\n");
1105 printf("stop feature:\n");
1106 printf(" Description:\n");
1107 printf(" Stops are debug instructions inserted by\n");
1108 printf(" the Assembler::stop() function.\n");
1109 printf(" When hitting a stop, the Simulator will\n");
1110 printf(" stop and and give control to the Debugger.\n");
1111 printf(" All stop codes are watched:\n");
1112 printf(" - They can be enabled / disabled: the Simulator\n");
1113 printf(" will / won't stop when hitting them.\n");
1114 printf(" - The Simulator keeps track of how many times they \n");
1115 printf(" are met. (See the info command.) Going over a\n");
1116 printf(" disabled stop still increases its counter. \n");
1117 printf(" Commands:\n");
1118 printf(" stop info all/<code> : print infos about number <code>\n");
1119 printf(" or all stop(s).\n");
1120 printf(" stop enable/disable all/<code> : enables / disables\n");
1121 printf(" all or number <code> stop(s)\n");
1122 printf(" stop unstop\n");
1123 printf(" ignore the stop instruction at the current location\n");
1124 printf(" from now on\n");
1125 } else {
1126 printf("Unknown command: %s\n", cmd);
1127 }
1128 }
1129 }
1130
1131 // Add all the breakpoints back to stop execution and enter the debugger
1132 // shell when hit.
1133 redoBreakpoints();
1134
1135 #undef COMMAND_SIZE
1136 #undef ARG_SIZE
1137
1138 #undef STR
1139 #undef XSTR
1140 }
1141
1142 static bool
AllOnOnePage(uintptr_t start,int size)1143 AllOnOnePage(uintptr_t start, int size)
1144 {
1145 intptr_t start_page = (start & ~CachePage::kPageMask);
1146 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
1147 return start_page == end_page;
1148 }
1149
1150 void
setLastDebuggerInput(char * input)1151 Simulator::setLastDebuggerInput(char* input)
1152 {
1153 js_free(lastDebuggerInput_);
1154 lastDebuggerInput_ = input;
1155 }
1156
1157 static CachePage*
GetCachePageLocked(Simulator::ICacheMap & i_cache,void * page)1158 GetCachePageLocked(Simulator::ICacheMap& i_cache, void* page)
1159 {
1160 Simulator::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
1161 if (p)
1162 return p->value();
1163
1164 CachePage* new_page = js_new<CachePage>();
1165 if (!i_cache.add(p, page, new_page))
1166 return nullptr;
1167 return new_page;
1168 }
1169
1170 // Flush from start up to and not including start + size.
1171 static void
FlushOnePageLocked(Simulator::ICacheMap & i_cache,intptr_t start,int size)1172 FlushOnePageLocked(Simulator::ICacheMap& i_cache, intptr_t start, int size)
1173 {
1174 MOZ_ASSERT(size <= CachePage::kPageSize);
1175 MOZ_ASSERT(AllOnOnePage(start, size - 1));
1176 MOZ_ASSERT((start & CachePage::kLineMask) == 0);
1177 MOZ_ASSERT((size & CachePage::kLineMask) == 0);
1178 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
1179 int offset = (start & CachePage::kPageMask);
1180 CachePage* cache_page = GetCachePageLocked(i_cache, page);
1181 char* valid_bytemap = cache_page->validityByte(offset);
1182 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
1183 }
1184
1185 static void
FlushICacheLocked(Simulator::ICacheMap & i_cache,void * start_addr,size_t size)1186 FlushICacheLocked(Simulator::ICacheMap& i_cache, void* start_addr, size_t size)
1187 {
1188 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
1189 int intra_line = (start & CachePage::kLineMask);
1190 start -= intra_line;
1191 size += intra_line;
1192 size = ((size - 1) | CachePage::kLineMask) + 1;
1193 int offset = (start & CachePage::kPageMask);
1194 while (!AllOnOnePage(start, size - 1)) {
1195 int bytes_to_flush = CachePage::kPageSize - offset;
1196 FlushOnePageLocked(i_cache, start, bytes_to_flush);
1197 start += bytes_to_flush;
1198 size -= bytes_to_flush;
1199 MOZ_ASSERT((start & CachePage::kPageMask) == 0);
1200 offset = 0;
1201 }
1202 if (size != 0)
1203 FlushOnePageLocked(i_cache, start, size);
1204 }
1205
1206 static void
CheckICacheLocked(Simulator::ICacheMap & i_cache,SimInstruction * instr)1207 CheckICacheLocked(Simulator::ICacheMap& i_cache, SimInstruction* instr)
1208 {
1209 intptr_t address = reinterpret_cast<intptr_t>(instr);
1210 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
1211 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
1212 int offset = (address & CachePage::kPageMask);
1213 CachePage* cache_page = GetCachePageLocked(i_cache, page);
1214 char* cache_valid_byte = cache_page->validityByte(offset);
1215 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
1216 char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
1217 if (cache_hit) {
1218 // Check that the data in memory matches the contents of the I-cache.
1219 MOZ_ASSERT(memcmp(reinterpret_cast<void*>(instr),
1220 cache_page->cachedData(offset),
1221 SimInstruction::kInstrSize) == 0);
1222 } else {
1223 // Cache miss. Load memory into the cache.
1224 memcpy(cached_line, line, CachePage::kLineLength);
1225 *cache_valid_byte = CachePage::LINE_VALID;
1226 }
1227 }
1228
1229 HashNumber
hash(const Lookup & l)1230 Simulator::ICacheHasher::hash(const Lookup& l)
1231 {
1232 return U32(reinterpret_cast<uintptr_t>(l)) >> 2;
1233 }
1234
1235 bool
match(const Key & k,const Lookup & l)1236 Simulator::ICacheHasher::match(const Key& k, const Lookup& l)
1237 {
1238 MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
1239 MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
1240 return k == l;
1241 }
1242
1243 void
FlushICache(void * start_addr,size_t size)1244 Simulator::FlushICache(void* start_addr, size_t size)
1245 {
1246 if (Simulator::ICacheCheckingEnabled) {
1247 Simulator* sim = Simulator::Current();
1248 AutoLockSimulatorCache als(sim);
1249 js::jit::FlushICacheLocked(sim->icache(), start_addr, size);
1250 }
1251 }
1252
Simulator()1253 Simulator::Simulator()
1254 {
1255 // Set up simulator support first. Some of this information is needed to
1256 // setup the architecture state.
1257
1258 // Note, allocation and anything that depends on allocated memory is
1259 // deferred until init(), in order to handle OOM properly.
1260
1261 stack_ = nullptr;
1262 stackLimit_ = 0;
1263 pc_modified_ = false;
1264 icount_ = 0;
1265 break_count_ = 0;
1266 resume_pc_ = 0;
1267 break_pc_ = nullptr;
1268 break_instr_ = 0;
1269 single_stepping_ = false;
1270 single_step_callback_ = nullptr;
1271 single_step_callback_arg_ = nullptr;
1272
1273 // Set up architecture state.
1274 // All registers are initialized to zero to start with.
1275 for (int i = 0; i < Register::kNumSimuRegisters; i++)
1276 registers_[i] = 0;
1277 for (int i = 0; i < Simulator::FPURegister::kNumFPURegisters; i++)
1278 FPUregisters_[i] = 0;
1279 FCSR_ = 0;
1280
1281 // The ra and pc are initialized to a known bad value that will cause an
1282 // access violation if the simulator ever tries to execute it.
1283 registers_[pc] = bad_ra;
1284 registers_[ra] = bad_ra;
1285
1286 for (int i = 0; i < kNumExceptions; i++)
1287 exceptions[i] = 0;
1288
1289 lastDebuggerInput_ = nullptr;
1290
1291 cacheLock_ = nullptr;
1292 #ifdef DEBUG
1293 cacheLockHolder_ = nullptr;
1294 #endif
1295 redirection_ = nullptr;
1296 }
1297
1298 bool
init()1299 Simulator::init()
1300 {
1301 cacheLock_ = PR_NewLock();
1302 if (!cacheLock_)
1303 return false;
1304
1305 if (!icache_.init())
1306 return false;
1307
1308 // Allocate 2MB for the stack. Note that we will only use 1MB, see below.
1309 static const size_t stackSize = 2 * 1024 * 1024;
1310 stack_ = static_cast<char*>(js_malloc(stackSize));
1311 if (!stack_)
1312 return false;
1313
1314 // Leave a safety margin of 1MB to prevent overrunning the stack when
1315 // pushing values (total stack size is 2MB).
1316 stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
1317
1318 // The sp is initialized to point to the bottom (high address) of the
1319 // allocated stack area. To be safe in potential stack underflows we leave
1320 // some buffer below.
1321 registers_[sp] = reinterpret_cast<int64_t>(stack_) + stackSize - 64;
1322
1323 return true;
1324 }
1325
1326 // When the generated code calls an external reference we need to catch that in
1327 // the simulator. The external reference will be a function compiled for the
1328 // host architecture. We need to call that function instead of trying to
1329 // execute it with the simulator. We do that by redirecting the external
1330 // reference to a swi (software-interrupt) instruction that is handled by
1331 // the simulator. We write the original destination of the jump just at a known
1332 // offset from the swi instruction so the simulator knows what to call.
1333 class Redirection
1334 {
1335 friend class Simulator;
1336
1337 // sim's lock must already be held.
Redirection(void * nativeFunction,ABIFunctionType type,Simulator * sim)1338 Redirection(void* nativeFunction, ABIFunctionType type, Simulator* sim)
1339 : nativeFunction_(nativeFunction),
1340 swiInstruction_(kCallRedirInstr),
1341 type_(type),
1342 next_(nullptr)
1343 {
1344 next_ = sim->redirection();
1345 if (Simulator::ICacheCheckingEnabled)
1346 FlushICacheLocked(sim->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
1347 sim->setRedirection(this);
1348 }
1349
1350 public:
addressOfSwiInstruction()1351 void* addressOfSwiInstruction() { return &swiInstruction_; }
nativeFunction() const1352 void* nativeFunction() const { return nativeFunction_; }
type() const1353 ABIFunctionType type() const { return type_; }
1354
Get(void * nativeFunction,ABIFunctionType type)1355 static Redirection* Get(void* nativeFunction, ABIFunctionType type) {
1356 Simulator* sim = Simulator::Current();
1357
1358 AutoLockSimulatorCache als(sim);
1359
1360 Redirection* current = sim->redirection();
1361 for (; current != nullptr; current = current->next_) {
1362 if (current->nativeFunction_ == nativeFunction) {
1363 MOZ_ASSERT(current->type() == type);
1364 return current;
1365 }
1366 }
1367
1368 Redirection* redir = (Redirection*)js_malloc(sizeof(Redirection));
1369 if (!redir) {
1370 MOZ_ReportAssertionFailure("[unhandlable oom] Simulator redirection",
1371 __FILE__, __LINE__);
1372 MOZ_CRASH();
1373 }
1374 new(redir) Redirection(nativeFunction, type, sim);
1375 return redir;
1376 }
1377
FromSwiInstruction(SimInstruction * swiInstruction)1378 static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) {
1379 uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
1380 uint8_t* addrOfRedirection = addrOfSwi - offsetof(Redirection, swiInstruction_);
1381 return reinterpret_cast<Redirection*>(addrOfRedirection);
1382 }
1383
1384 private:
1385 void* nativeFunction_;
1386 uint32_t swiInstruction_;
1387 ABIFunctionType type_;
1388 Redirection* next_;
1389 };
1390
~Simulator()1391 Simulator::~Simulator()
1392 {
1393 js_free(stack_);
1394 PR_DestroyLock(cacheLock_);
1395 Redirection* r = redirection_;
1396 while (r) {
1397 Redirection* next = r->next_;
1398 js_delete(r);
1399 r = next;
1400 }
1401 }
1402
1403 /* static */ void*
RedirectNativeFunction(void * nativeFunction,ABIFunctionType type)1404 Simulator::RedirectNativeFunction(void* nativeFunction, ABIFunctionType type)
1405 {
1406 Redirection* redirection = Redirection::Get(nativeFunction, type);
1407 return redirection->addressOfSwiInstruction();
1408 }
1409
1410 // Get the active Simulator for the current thread.
1411 Simulator*
Current()1412 Simulator::Current()
1413 {
1414 return TlsPerThreadData.get()->simulator();
1415 }
1416
1417 // Sets the register in the architecture state. It will also deal with updating
1418 // Simulator internal state for special registers such as PC.
1419 void
setRegister(int reg,int64_t value)1420 Simulator::setRegister(int reg, int64_t value)
1421 {
1422 MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
1423 if (reg == pc)
1424 pc_modified_ = true;
1425
1426 // Zero register always holds 0.
1427 registers_[reg] = (reg == 0) ? 0 : value;
1428 }
1429
1430 void
setFpuRegister(int fpureg,int64_t value)1431 Simulator::setFpuRegister(int fpureg, int64_t value)
1432 {
1433 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1434 FPUregisters_[fpureg] = value;
1435 }
1436
1437 void
setFpuRegisterLo(int fpureg,int32_t value)1438 Simulator::setFpuRegisterLo(int fpureg, int32_t value)
1439 {
1440 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1441 *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]) = value;
1442 }
1443
1444 void
setFpuRegisterHi(int fpureg,int32_t value)1445 Simulator::setFpuRegisterHi(int fpureg, int32_t value)
1446 {
1447 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1448 *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1) = value;
1449 }
1450
1451 void
setFpuRegisterFloat(int fpureg,float value)1452 Simulator::setFpuRegisterFloat(int fpureg, float value)
1453 {
1454 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1455 *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]) = value;
1456 }
1457
1458 void
setFpuRegisterDouble(int fpureg,double value)1459 Simulator::setFpuRegisterDouble(int fpureg, double value)
1460 {
1461 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1462 *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]) = value;
1463 }
1464
1465 // Get the register from the architecture state. This function does handle
1466 // the special case of accessing the PC register.
1467 int64_t
getRegister(int reg) const1468 Simulator::getRegister(int reg) const
1469 {
1470 MOZ_ASSERT((reg >= 0) && (reg < Register::kNumSimuRegisters));
1471 if (reg == 0)
1472 return 0;
1473 return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
1474 }
1475
1476 int64_t
getFpuRegister(int fpureg) const1477 Simulator::getFpuRegister(int fpureg) const
1478 {
1479 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1480 return FPUregisters_[fpureg];
1481 }
1482
1483 int32_t
getFpuRegisterLo(int fpureg) const1484 Simulator::getFpuRegisterLo(int fpureg) const
1485 {
1486 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1487 return *mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg]);
1488 }
1489
1490 int32_t
getFpuRegisterHi(int fpureg) const1491 Simulator::getFpuRegisterHi(int fpureg) const
1492 {
1493 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1494 return *((mozilla::BitwiseCast<int32_t*>(&FPUregisters_[fpureg])) + 1);
1495 }
1496
1497 float
getFpuRegisterFloat(int fpureg) const1498 Simulator::getFpuRegisterFloat(int fpureg) const
1499 {
1500 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1501 return *mozilla::BitwiseCast<float*>(&FPUregisters_[fpureg]);
1502 }
1503
1504 double
getFpuRegisterDouble(int fpureg) const1505 Simulator::getFpuRegisterDouble(int fpureg) const
1506 {
1507 MOZ_ASSERT((fpureg >= 0) && (fpureg < Simulator::FPURegister::kNumFPURegisters));
1508 return *mozilla::BitwiseCast<double*>(&FPUregisters_[fpureg]);
1509 }
1510
1511 void
setCallResultDouble(double result)1512 Simulator::setCallResultDouble(double result)
1513 {
1514 setFpuRegisterDouble(f0, result);
1515 }
1516
1517 void
setCallResultFloat(float result)1518 Simulator::setCallResultFloat(float result)
1519 {
1520 setFpuRegisterFloat(f0, result);
1521 }
1522
1523 void
setCallResult(int64_t res)1524 Simulator::setCallResult(int64_t res)
1525 {
1526 setRegister(v0, res);
1527 }
1528
1529 void
setCallResult(__int128_t res)1530 Simulator::setCallResult(__int128_t res)
1531 {
1532 setRegister(v0, I64(res));
1533 setRegister(v1, I64(res >> 64));
1534 }
1535
1536 // Helper functions for setting and testing the FCSR register's bits.
1537 void
setFCSRBit(uint32_t cc,bool value)1538 Simulator::setFCSRBit(uint32_t cc, bool value)
1539 {
1540 if (value)
1541 FCSR_ |= (1 << cc);
1542 else
1543 FCSR_ &= ~(1 << cc);
1544 }
1545
1546 bool
testFCSRBit(uint32_t cc)1547 Simulator::testFCSRBit(uint32_t cc)
1548 {
1549 return FCSR_ & (1 << cc);
1550 }
1551
1552 // Sets the rounding error codes in FCSR based on the result of the rounding.
1553 // Returns true if the operation was invalid.
1554 bool
setFCSRRoundError(double original,double rounded)1555 Simulator::setFCSRRoundError(double original, double rounded)
1556 {
1557 bool ret = false;
1558
1559 if (!std::isfinite(original) || !std::isfinite(rounded)) {
1560 setFCSRBit(kFCSRInvalidOpFlagBit, true);
1561 ret = true;
1562 }
1563
1564 if (original != rounded)
1565 setFCSRBit(kFCSRInexactFlagBit, true);
1566
1567 if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
1568 setFCSRBit(kFCSRUnderflowFlagBit, true);
1569 ret = true;
1570 }
1571
1572 if (rounded > INT_MAX || rounded < INT_MIN) {
1573 setFCSRBit(kFCSROverflowFlagBit, true);
1574 // The reference is not really clear but it seems this is required:
1575 setFCSRBit(kFCSRInvalidOpFlagBit, true);
1576 ret = true;
1577 }
1578
1579 return ret;
1580 }
1581
1582 // Raw access to the PC register.
1583 void
set_pc(int64_t value)1584 Simulator::set_pc(int64_t value)
1585 {
1586 pc_modified_ = true;
1587 registers_[pc] = value;
1588 }
1589
1590 bool
has_bad_pc() const1591 Simulator::has_bad_pc() const
1592 {
1593 return ((registers_[pc] == bad_ra) || (registers_[pc] == end_sim_pc));
1594 }
1595
1596 // Raw access to the PC register without the special adjustment when reading.
1597 int64_t
get_pc() const1598 Simulator::get_pc() const
1599 {
1600 return registers_[pc];
1601 }
1602
1603 // The MIPS cannot do unaligned reads and writes. On some MIPS platforms an
1604 // interrupt is caused. On others it does a funky rotation thing. For now we
1605 // simply disallow unaligned reads, but at some point we may want to move to
1606 // emulating the rotate behaviour. Note that simulator runs have the runtime
1607 // system running directly on the host system and only generated code is
1608 // executed in the simulator. Since the host is typically IA32 we will not
1609 // get the correct MIPS-like behaviour on unaligned accesses.
1610
1611 uint8_t
readBU(uint64_t addr,SimInstruction * instr)1612 Simulator::readBU(uint64_t addr, SimInstruction* instr)
1613 {
1614 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1615 return* ptr;
1616 }
1617
1618 int8_t
readB(uint64_t addr,SimInstruction * instr)1619 Simulator::readB(uint64_t addr, SimInstruction* instr)
1620 {
1621 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1622 return* ptr;
1623 }
1624
1625 void
writeB(uint64_t addr,uint8_t value,SimInstruction * instr)1626 Simulator::writeB(uint64_t addr, uint8_t value, SimInstruction* instr)
1627 {
1628 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr);
1629 *ptr = value;
1630 }
1631
1632 void
writeB(uint64_t addr,int8_t value,SimInstruction * instr)1633 Simulator::writeB(uint64_t addr, int8_t value, SimInstruction* instr)
1634 {
1635 int8_t* ptr = reinterpret_cast<int8_t*>(addr);
1636 *ptr = value;
1637 }
1638
1639 uint16_t
readHU(uint64_t addr,SimInstruction * instr)1640 Simulator::readHU(uint64_t addr, SimInstruction* instr)
1641 {
1642 if ((addr & 1) == 0) {
1643 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1644 return *ptr;
1645 }
1646 printf("Unaligned unsigned halfword read at 0x%016lx, pc=0x%016lx\n",
1647 addr, reinterpret_cast<intptr_t>(instr));
1648 MOZ_CRASH();
1649 return 0;
1650 }
1651
1652 int16_t
readH(uint64_t addr,SimInstruction * instr)1653 Simulator::readH(uint64_t addr, SimInstruction* instr)
1654 {
1655 if ((addr & 1) == 0) {
1656 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1657 return *ptr;
1658 }
1659 printf("Unaligned signed halfword read at 0x%016lx, pc=0x%016lx\n",
1660 addr, reinterpret_cast<intptr_t>(instr));
1661 MOZ_CRASH();
1662 return 0;
1663 }
1664
1665 void
writeH(uint64_t addr,uint16_t value,SimInstruction * instr)1666 Simulator::writeH(uint64_t addr, uint16_t value, SimInstruction* instr)
1667 {
1668 if ((addr & 1) == 0) {
1669 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
1670 *ptr = value;
1671 return;
1672 }
1673 printf("Unaligned unsigned halfword write at 0x%016lx, pc=0x%016lx\n",
1674 addr, reinterpret_cast<intptr_t>(instr));
1675 MOZ_CRASH();
1676 }
1677
1678 void
writeH(uint64_t addr,int16_t value,SimInstruction * instr)1679 Simulator::writeH(uint64_t addr, int16_t value, SimInstruction* instr)
1680 {
1681 if ((addr & 1) == 0) {
1682 int16_t* ptr = reinterpret_cast<int16_t*>(addr);
1683 *ptr = value;
1684 return;
1685 }
1686 printf("Unaligned halfword write at 0x%016lx, pc=0x%016lx\n",
1687 addr, reinterpret_cast<intptr_t>(instr));
1688 MOZ_CRASH();
1689 }
1690
1691 uint32_t
readWU(uint64_t addr,SimInstruction * instr)1692 Simulator::readWU(uint64_t addr, SimInstruction* instr)
1693 {
1694 if (addr < 0x400) {
1695 // This has to be a NULL-dereference, drop into debugger.
1696 printf("Memory read from bad address: 0x%016lx, pc=0x%016lx\n",
1697 addr, reinterpret_cast<intptr_t>(instr));
1698 MOZ_CRASH();
1699 }
1700 if ((addr & 3) == 0) {
1701 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1702 return *ptr;
1703 }
1704 printf("Unaligned read at 0x%016lx, pc=0x%016lx\n",
1705 addr, reinterpret_cast<intptr_t>(instr));
1706 MOZ_CRASH();
1707 return 0;
1708 }
1709
1710 int32_t
readW(uint64_t addr,SimInstruction * instr)1711 Simulator::readW(uint64_t addr, SimInstruction* instr)
1712 {
1713 if (addr < 0x400) {
1714 // This has to be a NULL-dereference, drop into debugger.
1715 printf("Memory read from bad address: 0x%016lx, pc=0x%016lx\n",
1716 addr, reinterpret_cast<intptr_t>(instr));
1717 MOZ_CRASH();
1718 }
1719 if ((addr & 3) == 0) {
1720 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1721 return *ptr;
1722 }
1723 printf("Unaligned read at 0x%016lx, pc=0x%016lx\n",
1724 addr, reinterpret_cast<intptr_t>(instr));
1725 MOZ_CRASH();
1726 return 0;
1727 }
1728
1729 void
writeW(uint64_t addr,uint32_t value,SimInstruction * instr)1730 Simulator::writeW(uint64_t addr, uint32_t value, SimInstruction* instr)
1731 {
1732 if (addr < 0x400) {
1733 // This has to be a NULL-dereference, drop into debugger.
1734 printf("Memory write to bad address: 0x%016lx, pc=0x%016lx\n",
1735 addr, reinterpret_cast<intptr_t>(instr));
1736 MOZ_CRASH();
1737 }
1738 if ((addr & 3) == 0) {
1739 uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
1740 *ptr = value;
1741 return;
1742 }
1743 printf("Unaligned write at 0x%016lx, pc=0x%016lx\n",
1744 addr, reinterpret_cast<intptr_t>(instr));
1745 MOZ_CRASH();
1746 }
1747
1748 void
writeW(uint64_t addr,int32_t value,SimInstruction * instr)1749 Simulator::writeW(uint64_t addr, int32_t value, SimInstruction* instr)
1750 {
1751 if (addr < 0x400) {
1752 // This has to be a NULL-dereference, drop into debugger.
1753 printf("Memory write to bad address: 0x%016lx, pc=0x%016lx\n",
1754 addr, reinterpret_cast<intptr_t>(instr));
1755 MOZ_CRASH();
1756 }
1757 if ((addr & 3) == 0) {
1758 int32_t* ptr = reinterpret_cast<int32_t*>(addr);
1759 *ptr = value;
1760 return;
1761 }
1762 printf("Unaligned write at 0x%016lx, pc=0x%016lx\n",
1763 addr, reinterpret_cast<intptr_t>(instr));
1764 MOZ_CRASH();
1765 }
1766
1767 int64_t
readDW(uint64_t addr,SimInstruction * instr)1768 Simulator::readDW(uint64_t addr, SimInstruction* instr)
1769 {
1770 if (addr < 0x400) {
1771 // This has to be a NULL-dereference, drop into debugger.
1772 printf("Memory read from bad address: 0x%016lx, pc=0x%016lx\n",
1773 addr, reinterpret_cast<intptr_t>(instr));
1774 MOZ_CRASH();
1775 }
1776 if ((addr & kPointerAlignmentMask) == 0) {
1777 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1778 return* ptr;
1779 }
1780 printf("Unaligned read at 0x%016lx, pc=0x%016lx\n",
1781 addr, reinterpret_cast<intptr_t>(instr));
1782 MOZ_CRASH();
1783 return 0;
1784 }
1785
1786 void
writeDW(uint64_t addr,int64_t value,SimInstruction * instr)1787 Simulator::writeDW(uint64_t addr, int64_t value, SimInstruction* instr)
1788 {
1789 if (addr < 0x400) {
1790 // This has to be a NULL-dereference, drop into debugger.
1791 printf("Memory write to bad address: 0x%016lx, pc=0x%016lx\n",
1792 addr, reinterpret_cast<intptr_t>(instr));
1793 MOZ_CRASH();
1794 }
1795 if ((addr & kPointerAlignmentMask) == 0) {
1796 int64_t* ptr = reinterpret_cast<int64_t*>(addr);
1797 *ptr = value;
1798 return;
1799 }
1800 printf("Unaligned write at 0x%016lx, pc=0x%016lx\n",
1801 addr, reinterpret_cast<intptr_t>(instr));
1802 MOZ_CRASH();
1803 }
1804
1805 double
readD(uint64_t addr,SimInstruction * instr)1806 Simulator::readD(uint64_t addr, SimInstruction* instr)
1807 {
1808 if ((addr & kDoubleAlignmentMask) == 0) {
1809 double* ptr = reinterpret_cast<double*>(addr);
1810 return *ptr;
1811 }
1812 printf("Unaligned (double) read at 0x%016lx, pc=0x%016lx\n",
1813 addr, reinterpret_cast<intptr_t>(instr));
1814 MOZ_CRASH();
1815 return 0;
1816 }
1817
1818 void
writeD(uint64_t addr,double value,SimInstruction * instr)1819 Simulator::writeD(uint64_t addr, double value, SimInstruction* instr)
1820 {
1821 if ((addr & kDoubleAlignmentMask) == 0) {
1822 double* ptr = reinterpret_cast<double*>(addr);
1823 *ptr = value;
1824 return;
1825 }
1826 printf("Unaligned (double) write at 0x%016lx, pc=0x%016lx\n",
1827 addr, reinterpret_cast<intptr_t>(instr));
1828 MOZ_CRASH();
1829 }
1830
1831 uintptr_t
stackLimit() const1832 Simulator::stackLimit() const
1833 {
1834 return stackLimit_;
1835 }
1836
1837 uintptr_t*
addressOfStackLimit()1838 Simulator::addressOfStackLimit()
1839 {
1840 return &stackLimit_;
1841 }
1842
1843 bool
overRecursed(uintptr_t newsp) const1844 Simulator::overRecursed(uintptr_t newsp) const
1845 {
1846 if (newsp == 0)
1847 newsp = getRegister(sp);
1848 return newsp <= stackLimit();
1849 }
1850
1851 bool
overRecursedWithExtra(uint32_t extra) const1852 Simulator::overRecursedWithExtra(uint32_t extra) const
1853 {
1854 uintptr_t newsp = getRegister(sp) - extra;
1855 return newsp <= stackLimit();
1856 }
1857
1858 // Unsupported instructions use format to print an error and stop execution.
1859 void
format(SimInstruction * instr,const char * format)1860 Simulator::format(SimInstruction* instr, const char* format)
1861 {
1862 printf("Simulator found unsupported instruction:\n 0x%016lx: %s\n",
1863 reinterpret_cast<intptr_t>(instr), format);
1864 MOZ_CRASH();
1865 }
1866
1867 // Note: With the code below we assume that all runtime calls return a 64 bits
1868 // result. If they don't, the v1 result register contains a bogus value, which
1869 // is fine because it is caller-saved.
1870 typedef int64_t (*Prototype_General0)();
1871 typedef int64_t (*Prototype_General1)(int64_t arg0);
1872 typedef int64_t (*Prototype_General2)(int64_t arg0, int64_t arg1);
1873 typedef int64_t (*Prototype_General3)(int64_t arg0, int64_t arg1, int64_t arg2);
1874 typedef int64_t (*Prototype_General4)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3);
1875 typedef int64_t (*Prototype_General5)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
1876 int64_t arg4);
1877 typedef int64_t (*Prototype_General6)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
1878 int64_t arg4, int64_t arg5);
1879 typedef int64_t (*Prototype_General7)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
1880 int64_t arg4, int64_t arg5, int64_t arg6);
1881 typedef int64_t (*Prototype_General8)(int64_t arg0, int64_t arg1, int64_t arg2, int64_t arg3,
1882 int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg7);
1883
1884 typedef double (*Prototype_Double_None)();
1885 typedef double (*Prototype_Double_Double)(double arg0);
1886 typedef double (*Prototype_Double_Int)(int64_t arg0);
1887 typedef int64_t (*Prototype_Int_Double)(double arg0);
1888 typedef int64_t (*Prototype_Int_DoubleIntInt)(double arg0, int64_t arg1, int64_t arg2);
1889 typedef int64_t (*Prototype_Int_IntDoubleIntInt)(int64_t arg0, double arg1, int64_t arg2,
1890 int64_t arg3);
1891 typedef float (*Prototype_Float32_Float32)(float arg0);
1892
1893 typedef double (*Prototype_DoubleInt)(double arg0, int64_t arg1);
1894 typedef double (*Prototype_Double_IntDouble)(int64_t arg0, double arg1);
1895 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
1896 typedef int64_t (*Prototype_Int_IntDouble)(int64_t arg0, double arg1);
1897
1898 typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
1899 typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
1900 double arg2, double arg3);
1901
1902 // Software interrupt instructions are used by the simulator to call into C++.
1903 void
softwareInterrupt(SimInstruction * instr)1904 Simulator::softwareInterrupt(SimInstruction* instr)
1905 {
1906 int32_t func = instr->functionFieldRaw();
1907 uint32_t code = (func == ff_break) ? instr->bits(25, 6) : -1;
1908
1909 // We first check if we met a call_rt_redirected.
1910 if (instr->instructionBits() == kCallRedirInstr) {
1911 #if !defined(USES_N64_ABI)
1912 MOZ_CRASH("Only N64 ABI supported.");
1913 #else
1914 Redirection* redirection = Redirection::FromSwiInstruction(instr);
1915 int64_t arg0 = getRegister(a0);
1916 int64_t arg1 = getRegister(a1);
1917 int64_t arg2 = getRegister(a2);
1918 int64_t arg3 = getRegister(a3);
1919 int64_t arg4 = getRegister(a4);
1920 int64_t arg5 = getRegister(a5);
1921
1922 // This is dodgy but it works because the C entry stubs are never moved.
1923 // See comment in codegen-arm.cc and bug 1242173.
1924 int64_t saved_ra = getRegister(ra);
1925
1926 intptr_t external = reinterpret_cast<intptr_t>(redirection->nativeFunction());
1927
1928 bool stack_aligned = (getRegister(sp) & (ABIStackAlignment - 1)) == 0;
1929 if (!stack_aligned) {
1930 fprintf(stderr, "Runtime call with unaligned stack!\n");
1931 MOZ_CRASH();
1932 }
1933
1934 if (single_stepping_)
1935 single_step_callback_(single_step_callback_arg_, this, nullptr);
1936
1937 switch (redirection->type()) {
1938 case Args_General0: {
1939 Prototype_General0 target = reinterpret_cast<Prototype_General0>(external);
1940 int64_t result = target();
1941 setCallResult(result);
1942 break;
1943 }
1944 case Args_General1: {
1945 Prototype_General1 target = reinterpret_cast<Prototype_General1>(external);
1946 int64_t result = target(arg0);
1947 setCallResult(result);
1948 break;
1949 }
1950 case Args_General2: {
1951 Prototype_General2 target = reinterpret_cast<Prototype_General2>(external);
1952 int64_t result = target(arg0, arg1);
1953 setCallResult(result);
1954 break;
1955 }
1956 case Args_General3: {
1957 Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
1958 int64_t result = target(arg0, arg1, arg2);
1959 setCallResult(result);
1960 break;
1961 }
1962 case Args_General4: {
1963 Prototype_General4 target = reinterpret_cast<Prototype_General4>(external);
1964 int64_t result = target(arg0, arg1, arg2, arg3);
1965 setCallResult(result);
1966 break;
1967 }
1968 case Args_General5: {
1969 Prototype_General5 target = reinterpret_cast<Prototype_General5>(external);
1970 int64_t result = target(arg0, arg1, arg2, arg3, arg4);
1971 setCallResult(result);
1972 break;
1973 }
1974 case Args_General6: {
1975 Prototype_General6 target = reinterpret_cast<Prototype_General6>(external);
1976 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
1977 setCallResult(result);
1978 break;
1979 }
1980 case Args_General7: {
1981 Prototype_General7 target = reinterpret_cast<Prototype_General7>(external);
1982 int64_t arg6 = getRegister(a6);
1983 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
1984 setCallResult(result);
1985 break;
1986 }
1987 case Args_General8: {
1988 Prototype_General8 target = reinterpret_cast<Prototype_General8>(external);
1989 int64_t arg6 = getRegister(a6);
1990 int64_t arg7 = getRegister(a7);
1991 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
1992 setCallResult(result);
1993 break;
1994 }
1995 case Args_Double_None: {
1996 Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
1997 double dresult = target();
1998 setCallResultDouble(dresult);
1999 break;
2000 }
2001 case Args_Int_Double: {
2002 double dval0 = getFpuRegisterDouble(12);
2003 Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
2004 int64_t res = target(dval0);
2005 setRegister(v0, res);
2006 break;
2007 }
2008 case Args_Int_DoubleIntInt: {
2009 double dval = getFpuRegisterDouble(12);
2010 Prototype_Int_DoubleIntInt target = reinterpret_cast<Prototype_Int_DoubleIntInt>(external);
2011 int64_t res = target(dval, arg1, arg2);
2012 setRegister(v0, res);
2013 break;
2014 }
2015 case Args_Int_IntDoubleIntInt: {
2016 double dval = getFpuRegisterDouble(13);
2017 Prototype_Int_IntDoubleIntInt target = reinterpret_cast<Prototype_Int_IntDoubleIntInt>(external);
2018 int64_t res = target(arg0, dval, arg2, arg3);
2019 setRegister(v0, res);
2020 break;
2021 }
2022 case Args_Double_Double: {
2023 double dval0 = getFpuRegisterDouble(12);
2024 Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
2025 double dresult = target(dval0);
2026 setCallResultDouble(dresult);
2027 break;
2028 }
2029 case Args_Float32_Float32: {
2030 float fval0;
2031 fval0 = getFpuRegisterFloat(12);
2032 Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
2033 float fresult = target(fval0);
2034 setCallResultFloat(fresult);
2035 break;
2036 }
2037 case Args_Double_Int: {
2038 Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
2039 double dresult = target(arg0);
2040 setCallResultDouble(dresult);
2041 break;
2042 }
2043 case Args_Double_DoubleInt: {
2044 double dval0 = getFpuRegisterDouble(12);
2045 Prototype_DoubleInt target = reinterpret_cast<Prototype_DoubleInt>(external);
2046 double dresult = target(dval0, arg1);
2047 setCallResultDouble(dresult);
2048 break;
2049 }
2050 case Args_Double_DoubleDouble: {
2051 double dval0 = getFpuRegisterDouble(12);
2052 double dval1 = getFpuRegisterDouble(13);
2053 Prototype_Double_DoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDouble>(external);
2054 double dresult = target(dval0, dval1);
2055 setCallResultDouble(dresult);
2056 break;
2057 }
2058 case Args_Double_IntDouble: {
2059 double dval1 = getFpuRegisterDouble(13);
2060 Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
2061 double dresult = target(arg0, dval1);
2062 setCallResultDouble(dresult);
2063 break;
2064 }
2065 case Args_Int_IntDouble: {
2066 double dval1 = getFpuRegisterDouble(13);
2067 Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
2068 int64_t result = target(arg0, dval1);
2069 setRegister(v0, result);
2070 break;
2071 }
2072 case Args_Double_DoubleDoubleDouble: {
2073 double dval0 = getFpuRegisterDouble(12);
2074 double dval1 = getFpuRegisterDouble(13);
2075 double dval2 = getFpuRegisterDouble(14);
2076 Prototype_Double_DoubleDoubleDouble target =
2077 reinterpret_cast<Prototype_Double_DoubleDoubleDouble>(external);
2078 double dresult = target(dval0, dval1, dval2);
2079 setCallResultDouble(dresult);
2080 break;
2081 }
2082 case Args_Double_DoubleDoubleDoubleDouble: {
2083 double dval0 = getFpuRegisterDouble(12);
2084 double dval1 = getFpuRegisterDouble(13);
2085 double dval2 = getFpuRegisterDouble(14);
2086 double dval3 = getFpuRegisterDouble(15);
2087 Prototype_Double_DoubleDoubleDoubleDouble target =
2088 reinterpret_cast<Prototype_Double_DoubleDoubleDoubleDouble>(external);
2089 double dresult = target(dval0, dval1, dval2, dval3);
2090 setCallResultDouble(dresult);
2091 break;
2092 }
2093 default:
2094 MOZ_CRASH("call");
2095 }
2096
2097 if (single_stepping_)
2098 single_step_callback_(single_step_callback_arg_, this, nullptr);
2099
2100 setRegister(ra, saved_ra);
2101 set_pc(getRegister(ra));
2102 #endif
2103 } else if (func == ff_break && code <= kMaxStopCode) {
2104 if (isWatchpoint(code)) {
2105 printWatchpoint(code);
2106 } else {
2107 increaseStopCounter(code);
2108 handleStop(code, instr);
2109 }
2110 } else {
2111 // All remaining break_ codes, and all traps are handled here.
2112 MipsDebugger dbg(this);
2113 dbg.debug();
2114 }
2115 }
2116
2117 // Stop helper functions.
2118 bool
isWatchpoint(uint32_t code)2119 Simulator::isWatchpoint(uint32_t code)
2120 {
2121 return (code <= kMaxWatchpointCode);
2122 }
2123
2124 void
printWatchpoint(uint32_t code)2125 Simulator::printWatchpoint(uint32_t code)
2126 {
2127 MipsDebugger dbg(this);
2128 ++break_count_;
2129 printf("\n---- break %d marker: %20ld (instr count: %20ld) ----\n",
2130 code, break_count_, icount_);
2131 dbg.printAllRegs(); // Print registers and continue running.
2132 }
2133
2134 void
handleStop(uint32_t code,SimInstruction * instr)2135 Simulator::handleStop(uint32_t code, SimInstruction* instr)
2136 {
2137 // Stop if it is enabled, otherwise go on jumping over the stop
2138 // and the message address.
2139 if (isEnabledStop(code)) {
2140 MipsDebugger dbg(this);
2141 dbg.stop(instr);
2142 } else {
2143 set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
2144 }
2145 }
2146
2147 bool
isStopInstruction(SimInstruction * instr)2148 Simulator::isStopInstruction(SimInstruction* instr)
2149 {
2150 int32_t func = instr->functionFieldRaw();
2151 uint32_t code = U32(instr->bits(25, 6));
2152 return (func == ff_break) && code > kMaxWatchpointCode && code <= kMaxStopCode;
2153 }
2154
2155 bool
isEnabledStop(uint32_t code)2156 Simulator::isEnabledStop(uint32_t code)
2157 {
2158 MOZ_ASSERT(code <= kMaxStopCode);
2159 MOZ_ASSERT(code > kMaxWatchpointCode);
2160 return !(watchedStops_[code].count_ & kStopDisabledBit);
2161 }
2162
2163 void
enableStop(uint32_t code)2164 Simulator::enableStop(uint32_t code)
2165 {
2166 if (!isEnabledStop(code))
2167 watchedStops_[code].count_ &= ~kStopDisabledBit;
2168 }
2169
2170 void
disableStop(uint32_t code)2171 Simulator::disableStop(uint32_t code)
2172 {
2173 if (isEnabledStop(code))
2174 watchedStops_[code].count_ |= kStopDisabledBit;
2175 }
2176
2177 void
increaseStopCounter(uint32_t code)2178 Simulator::increaseStopCounter(uint32_t code)
2179 {
2180 MOZ_ASSERT(code <= kMaxStopCode);
2181 if ((watchedStops_[code].count_ & ~(1 << 31)) == 0x7fffffff) {
2182 printf("Stop counter for code %i has overflowed.\n"
2183 "Enabling this code and reseting the counter to 0.\n", code);
2184 watchedStops_[code].count_ = 0;
2185 enableStop(code);
2186 } else {
2187 watchedStops_[code].count_++;
2188 }
2189 }
2190
2191 // Print a stop status.
2192 void
printStopInfo(uint32_t code)2193 Simulator::printStopInfo(uint32_t code)
2194 {
2195 if (code <= kMaxWatchpointCode) {
2196 printf("That is a watchpoint, not a stop.\n");
2197 return;
2198 } else if (code > kMaxStopCode) {
2199 printf("Code too large, only %u stops can be used\n", kMaxStopCode + 1);
2200 return;
2201 }
2202 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled";
2203 int32_t count = watchedStops_[code].count_ & ~kStopDisabledBit;
2204 // Don't print the state of unused breakpoints.
2205 if (count != 0) {
2206 if (watchedStops_[code].desc_) {
2207 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
2208 code, code, state, count, watchedStops_[code].desc_);
2209 } else {
2210 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2211 code, code, state, count);
2212 }
2213 }
2214 }
2215
2216 void
signalExceptions()2217 Simulator::signalExceptions()
2218 {
2219 for (int i = 1; i < kNumExceptions; i++) {
2220 if (exceptions[i] != 0)
2221 MOZ_CRASH("Error: Exception raised.");
2222 }
2223 }
2224
2225 // Helper function for decodeTypeRegister.
2226 void
configureTypeRegister(SimInstruction * instr,int64_t & alu_out,__int128 & i128hilo,unsigned __int128 & u128hilo,int64_t & next_pc,int32_t & return_addr_reg,bool & do_interrupt)2227 Simulator::configureTypeRegister(SimInstruction* instr,
2228 int64_t& alu_out,
2229 __int128& i128hilo,
2230 unsigned __int128& u128hilo,
2231 int64_t& next_pc,
2232 int32_t& return_addr_reg,
2233 bool& do_interrupt)
2234 {
2235 // Every local variable declared here needs to be const.
2236 // This is to make sure that changed values are sent back to
2237 // decodeTypeRegister correctly.
2238
2239 // Instruction fields.
2240 const Opcode op = instr->opcodeFieldRaw();
2241 const int32_t rs_reg = instr->rsValue();
2242 const int64_t rs = getRegister(rs_reg);
2243 const int32_t rt_reg = instr->rtValue();
2244 const int64_t rt = getRegister(rt_reg);
2245 const int32_t rd_reg = instr->rdValue();
2246 const uint32_t sa = instr->saValue();
2247
2248 const int32_t fs_reg = instr->fsValue();
2249 __int128 temp;
2250
2251
2252 // ---------- Configuration.
2253 switch (op) {
2254 case op_cop1: // Coprocessor instructions.
2255 switch (instr->rsFieldRaw()) {
2256 case rs_bc1: // Handled in DecodeTypeImmed, should never come here.
2257 MOZ_CRASH();
2258 break;
2259 case rs_cfc1:
2260 // At the moment only FCSR is supported.
2261 MOZ_ASSERT(fs_reg == kFCSRRegister);
2262 alu_out = FCSR_;
2263 break;
2264 case rs_mfc1:
2265 alu_out = getFpuRegisterLo(fs_reg);
2266 break;
2267 case rs_dmfc1:
2268 alu_out = getFpuRegister(fs_reg);
2269 break;
2270 case rs_mfhc1:
2271 alu_out = getFpuRegisterHi(fs_reg);
2272 break;
2273 case rs_ctc1:
2274 case rs_mtc1:
2275 case rs_dmtc1:
2276 case rs_mthc1:
2277 // Do the store in the execution step.
2278 break;
2279 case rs_s:
2280 case rs_d:
2281 case rs_w:
2282 case rs_l:
2283 case rs_ps:
2284 // Do everything in the execution step.
2285 break;
2286 default:
2287 MOZ_CRASH();
2288 };
2289 break;
2290 case op_cop1x:
2291 break;
2292 case op_special:
2293 switch (instr->functionFieldRaw()) {
2294 case ff_jr:
2295 case ff_jalr:
2296 next_pc = getRegister(instr->rsValue());
2297 return_addr_reg = instr->rdValue();
2298 break;
2299 case ff_sll:
2300 alu_out = I32(rt) << sa;
2301 break;
2302 case ff_dsll:
2303 alu_out = rt << sa;
2304 break;
2305 case ff_dsll32:
2306 alu_out = rt << (sa + 32);
2307 break;
2308 case ff_srl:
2309 if (rs_reg == 0) {
2310 // Regular logical right shift of a word by a fixed number of
2311 // bits instruction. RS field is always equal to 0.
2312 alu_out = I32(U32(rt) >> sa);
2313 } else {
2314 // Logical right-rotate of a word by a fixed number of bits. This
2315 // is special case of SRL instruction, added in MIPS32 Release 2.
2316 // RS field is equal to 00001.
2317 alu_out = I32((U32(rt) >> sa) | (U32(rt) << (32 - sa)));
2318 }
2319 break;
2320 case ff_dsrl:
2321 if (rs_reg == 0) {
2322 // Regular logical right shift of a double word by a fixed number of
2323 // bits instruction. RS field is always equal to 0.
2324 alu_out = U64(rt) >> sa;
2325 } else {
2326 // Logical right-rotate of a word by a fixed number of bits. This
2327 // is special case of DSRL instruction, added in MIPS64 Release 2.
2328 // RS field is equal to 00001.
2329 alu_out = (U64(rt) >> sa) | (U64(rt) << (64 - sa));
2330 }
2331 break;
2332 case ff_dsrl32:
2333 if (rs_reg == 0) {
2334 // Regular logical right shift of a double word by a fixed number of
2335 // bits instruction. RS field is always equal to 0.
2336 alu_out = U64(rt) >> (sa + 32);
2337 } else {
2338 // Logical right-rotate of a double word by a fixed number of bits. This
2339 // is special case of DSRL instruction, added in MIPS64 Release 2.
2340 // RS field is equal to 00001.
2341 alu_out = (U64(rt) >> (sa + 32)) | (U64(rt) << (64 - (sa + 32)));
2342 }
2343 break;
2344 case ff_sra:
2345 alu_out = I32(rt) >> sa;
2346 break;
2347 case ff_dsra:
2348 alu_out = rt >> sa;
2349 break;
2350 case ff_dsra32:
2351 alu_out = rt >> (sa + 32);
2352 break;
2353 case ff_sllv:
2354 alu_out = I32(rt) << rs;
2355 break;
2356 case ff_dsllv:
2357 alu_out = rt << rs;
2358 break;
2359 case ff_srlv:
2360 if (sa == 0) {
2361 // Regular logical right-shift of a word by a variable number of
2362 // bits instruction. SA field is always equal to 0.
2363 alu_out = I32(U32(rt) >> rs);
2364 } else {
2365 // Logical right-rotate of a word by a variable number of bits.
2366 // This is special case od SRLV instruction, added in MIPS32
2367 // Release 2. SA field is equal to 00001.
2368 alu_out = I32((U32(rt) >> rs) | (U32(rt) << (32 - rs)));
2369 }
2370 break;
2371 case ff_dsrlv:
2372 if (sa == 0) {
2373 // Regular logical right-shift of a double word by a variable number of
2374 // bits instruction. SA field is always equal to 0.
2375 alu_out = U64(rt) >> rs;
2376 } else {
2377 // Logical right-rotate of a double word by a variable number of bits.
2378 // This is special case od DSRLV instruction, added in MIPS64
2379 // Release 2. SA field is equal to 00001.
2380 alu_out = (U64(rt) >> rs) | (U64(rt) << (64 - rs));
2381 }
2382 break;
2383 case ff_srav:
2384 alu_out = I32(rt) >> rs;
2385 break;
2386 case ff_dsrav:
2387 alu_out = rt >> rs;
2388 break;
2389 case ff_mfhi:
2390 alu_out = getRegister(HI);
2391 break;
2392 case ff_mflo:
2393 alu_out = getRegister(LO);
2394 break;
2395 case ff_mult:
2396 i128hilo = I32(rs) * I32(rt);
2397 break;
2398 case ff_dmult:
2399 i128hilo = I128(rs) * I128(rt);
2400 break;
2401 case ff_multu:
2402 u128hilo = U32(rs) * U32(rt);
2403 break;
2404 case ff_dmultu:
2405 u128hilo = U128(rs) * U128(rt);
2406 break;
2407 case ff_add:
2408 alu_out = I32(rs) + I32(rt);
2409 if ((alu_out << 32) != (alu_out << 31))
2410 exceptions[kIntegerOverflow] = 1;
2411 alu_out = I32(alu_out);
2412 break;
2413 case ff_dadd:
2414 temp = I128(rs) + I128(rt);
2415 if ((temp << 64) != (temp << 63))
2416 exceptions[kIntegerOverflow] = 1;
2417 alu_out = I64(temp);
2418 break;
2419 case ff_addu:
2420 alu_out = I32(U32(rs) + U32(rt));
2421 break;
2422 case ff_daddu:
2423 alu_out = rs + rt;
2424 break;
2425 case ff_sub:
2426 alu_out = I32(rs) - I32(rt);
2427 if ((alu_out << 32) != (alu_out << 31))
2428 exceptions[kIntegerUnderflow] = 1;
2429 alu_out = I32(alu_out);
2430 break;
2431 case ff_dsub:
2432 temp = I128(rs) - I128(rt);
2433 if ((temp << 64) != (temp << 63))
2434 exceptions[kIntegerUnderflow] = 1;
2435 alu_out = I64(temp);
2436 break;
2437 case ff_subu:
2438 alu_out = I32(U32(rs) - U32(rt));
2439 break;
2440 case ff_dsubu:
2441 alu_out = rs - rt;
2442 break;
2443 case ff_and:
2444 alu_out = rs & rt;
2445 break;
2446 case ff_or:
2447 alu_out = rs | rt;
2448 break;
2449 case ff_xor:
2450 alu_out = rs ^ rt;
2451 break;
2452 case ff_nor:
2453 alu_out = ~(rs | rt);
2454 break;
2455 case ff_slt:
2456 alu_out = rs < rt ? 1 : 0;
2457 break;
2458 case ff_sltu:
2459 alu_out = U64(rs) < U64(rt) ? 1 : 0;
2460 break;
2461 case ff_sync:
2462 break;
2463 // Break and trap instructions.
2464 case ff_break:
2465 do_interrupt = true;
2466 break;
2467 case ff_tge:
2468 do_interrupt = rs >= rt;
2469 break;
2470 case ff_tgeu:
2471 do_interrupt = U64(rs) >= U64(rt);
2472 break;
2473 case ff_tlt:
2474 do_interrupt = rs < rt;
2475 break;
2476 case ff_tltu:
2477 do_interrupt = U64(rs) < U64(rt);
2478 break;
2479 case ff_teq:
2480 do_interrupt = rs == rt;
2481 break;
2482 case ff_tne:
2483 do_interrupt = rs != rt;
2484 break;
2485 case ff_movn:
2486 case ff_movz:
2487 case ff_movci:
2488 // No action taken on decode.
2489 break;
2490 case ff_div:
2491 if (I32(rs) == INT_MIN && I32(rt) == -1) {
2492 i128hilo = U32(INT_MIN);
2493 } else {
2494 uint32_t div = I32(rs) / I32(rt);
2495 uint32_t mod = I32(rs) % I32(rt);
2496 i128hilo = (I64(mod) << 32) | div;
2497 }
2498 break;
2499 case ff_ddiv:
2500 if (I32(rs) == INT_MIN && I32(rt) == -1) {
2501 i128hilo = U64(INT64_MIN);
2502 } else {
2503 uint64_t div = rs / rt;
2504 uint64_t mod = rs % rt;
2505 i128hilo = (I128(mod) << 64) | div;
2506 }
2507 break;
2508 case ff_divu: {
2509 uint32_t div = U32(rs) / U32(rt);
2510 uint32_t mod = U32(rs) % U32(rt);
2511 i128hilo = (U64(mod) << 32) | div;
2512 }
2513 break;
2514 case ff_ddivu:
2515 if (0 == rt) {
2516 i128hilo = (I128(Unpredictable) << 64) | I64(Unpredictable);
2517 } else {
2518 uint64_t div = U64(rs) / U64(rt);
2519 uint64_t mod = U64(rs) % U64(rt);
2520 i128hilo = (I128(mod) << 64) | div;
2521 }
2522 break;
2523 default:
2524 MOZ_CRASH();
2525 };
2526 break;
2527 case op_special2:
2528 switch (instr->functionFieldRaw()) {
2529 case ff_mul:
2530 alu_out = I32(I32(rs) * I32(rt)); // Only the lower 32 bits are kept.
2531 break;
2532 case ff_clz:
2533 alu_out = U32(rs) ? __builtin_clz(U32(rs)) : 32;
2534 break;
2535 case ff_dclz:
2536 alu_out = U64(rs) ? __builtin_clzl(U64(rs)) : 64;
2537 break;
2538 default:
2539 MOZ_CRASH();
2540 };
2541 break;
2542 case op_special3:
2543 switch (instr->functionFieldRaw()) {
2544 case ff_ins: { // Mips64r2 instruction.
2545 // Interpret rd field as 5-bit msb of insert.
2546 uint16_t msb = rd_reg;
2547 // Interpret sa field as 5-bit lsb of insert.
2548 uint16_t lsb = sa;
2549 uint16_t size = msb - lsb + 1;
2550 uint32_t mask = (1 << size) - 1;
2551 if (lsb > msb)
2552 alu_out = Unpredictable;
2553 else
2554 alu_out = (U32(rt) & ~(mask << lsb)) | ((U32(rs) & mask) << lsb);
2555 break;
2556 }
2557 case ff_dins: { // Mips64r2 instruction.
2558 // Interpret rd field as 5-bit msb of insert.
2559 uint16_t msb = rd_reg;
2560 // Interpret sa field as 5-bit lsb of insert.
2561 uint16_t lsb = sa;
2562 uint16_t size = msb - lsb + 1;
2563 uint64_t mask = (1ul << size) - 1;
2564 if (lsb > msb)
2565 alu_out = Unpredictable;
2566 else
2567 alu_out = (U64(rt) & ~(mask << lsb)) | ((U64(rs) & mask) << lsb);
2568 break;
2569 }
2570 case ff_dinsm: { // Mips64r2 instruction.
2571 // Interpret rd field as 5-bit msb of insert.
2572 uint16_t msb = rd_reg;
2573 // Interpret sa field as 5-bit lsb of insert.
2574 uint16_t lsb = sa;
2575 uint16_t size = msb - lsb + 33;
2576 uint64_t mask = (1ul << size) - 1;
2577 alu_out = (U64(rt) & ~(mask << lsb)) | ((U64(rs) & mask) << lsb);
2578 break;
2579 }
2580 case ff_dinsu: { // Mips64r2 instruction.
2581 // Interpret rd field as 5-bit msb of insert.
2582 uint16_t msb = rd_reg;
2583 // Interpret sa field as 5-bit lsb of insert.
2584 uint16_t lsb = sa + 32;
2585 uint16_t size = msb - lsb + 33;
2586 uint64_t mask = (1ul << size) - 1;
2587 if (sa > msb)
2588 alu_out = Unpredictable;
2589 else
2590 alu_out = (U64(rt) & ~(mask << lsb)) | ((U64(rs) & mask) << lsb);
2591 break;
2592 }
2593 case ff_ext: { // Mips64r2 instruction.
2594 // Interpret rd field as 5-bit msb of extract.
2595 uint16_t msb = rd_reg;
2596 // Interpret sa field as 5-bit lsb of extract.
2597 uint16_t lsb = sa;
2598 uint16_t size = msb + 1;
2599 uint32_t mask = (1 << size) - 1;
2600 if ((lsb + msb) > 31)
2601 alu_out = Unpredictable;
2602 else
2603 alu_out = (U32(rs) & (mask << lsb)) >> lsb;
2604 break;
2605 }
2606 case ff_dext: { // Mips64r2 instruction.
2607 // Interpret rd field as 5-bit msb of extract.
2608 uint16_t msb = rd_reg;
2609 // Interpret sa field as 5-bit lsb of extract.
2610 uint16_t lsb = sa;
2611 uint16_t size = msb + 1;
2612 uint64_t mask = (1ul << size) - 1;
2613 alu_out = (U64(rs) & (mask << lsb)) >> lsb;
2614 break;
2615 }
2616 case ff_dextm: { // Mips64r2 instruction.
2617 // Interpret rd field as 5-bit msb of extract.
2618 uint16_t msb = rd_reg;
2619 // Interpret sa field as 5-bit lsb of extract.
2620 uint16_t lsb = sa;
2621 uint16_t size = msb + 33;
2622 uint64_t mask = (1ul << size) - 1;
2623 if ((lsb + msb + 32 + 1) > 64)
2624 alu_out = Unpredictable;
2625 else
2626 alu_out = (U64(rs) & (mask << lsb)) >> lsb;
2627 break;
2628 }
2629 case ff_dextu: { // Mips64r2 instruction.
2630 // Interpret rd field as 5-bit msb of extract.
2631 uint16_t msb = rd_reg;
2632 // Interpret sa field as 5-bit lsb of extract.
2633 uint16_t lsb = sa + 32;
2634 uint16_t size = msb + 1;
2635 uint64_t mask = (1ul << size) - 1;
2636 if ((lsb + msb + 1) > 64)
2637 alu_out = Unpredictable;
2638 else
2639 alu_out = (U64(rs) & (mask << lsb)) >> lsb;
2640 break;
2641 }
2642 case ff_bshfl: { // Mips32r2 instruction.
2643 if (16 == sa) // seb
2644 alu_out = I64(I8(rt));
2645 else if (24 == sa) // seh
2646 alu_out = I64(I16(rt));
2647 break;
2648 }
2649 default:
2650 MOZ_CRASH();
2651 };
2652 break;
2653 default:
2654 MOZ_CRASH();
2655 };
2656 }
2657
2658 // Handle execution based on instruction types.
2659 void
decodeTypeRegister(SimInstruction * instr)2660 Simulator::decodeTypeRegister(SimInstruction* instr)
2661 {
2662 // Instruction fields.
2663 const Opcode op = instr->opcodeFieldRaw();
2664 const int32_t rs_reg = instr->rsValue();
2665 const int64_t rs = getRegister(rs_reg);
2666 const int32_t rt_reg = instr->rtValue();
2667 const int64_t rt = getRegister(rt_reg);
2668 const int32_t rd_reg = instr->rdValue();
2669
2670 const int32_t fr_reg = instr->frValue();
2671 const int32_t fs_reg = instr->fsValue();
2672 const int32_t ft_reg = instr->ftValue();
2673 const int32_t fd_reg = instr->fdValue();
2674 __int128 i128hilo = 0;
2675 unsigned __int128 u128hilo = 0;
2676
2677 // ALU output.
2678 // It should not be used as is. Instructions using it should always
2679 // initialize it first.
2680 int64_t alu_out = 0x12345678;
2681
2682 // For break and trap instructions.
2683 bool do_interrupt = false;
2684
2685 // For jr and jalr.
2686 // Get current pc.
2687 int64_t current_pc = get_pc();
2688 // Next pc
2689 int64_t next_pc = 0;
2690 int32_t return_addr_reg = 31;
2691
2692 // Set up the variables if needed before executing the instruction.
2693 configureTypeRegister(instr,
2694 alu_out,
2695 i128hilo,
2696 u128hilo,
2697 next_pc,
2698 return_addr_reg,
2699 do_interrupt);
2700
2701 // ---------- Raise exceptions triggered.
2702 signalExceptions();
2703
2704 // ---------- Execution.
2705 switch (op) {
2706 case op_cop1:
2707 switch (instr->rsFieldRaw()) {
2708 case rs_bc1: // Branch on coprocessor condition.
2709 MOZ_CRASH();
2710 break;
2711 case rs_cfc1:
2712 setRegister(rt_reg, alu_out);
2713 case rs_mfc1:
2714 setRegister(rt_reg, alu_out);
2715 break;
2716 case rs_dmfc1:
2717 setRegister(rt_reg, alu_out);
2718 break;
2719 case rs_mfhc1:
2720 setRegister(rt_reg, alu_out);
2721 break;
2722 case rs_ctc1:
2723 // At the moment only FCSR is supported.
2724 MOZ_ASSERT(fs_reg == kFCSRRegister);
2725 FCSR_ = registers_[rt_reg];
2726 break;
2727 case rs_mtc1:
2728 setFpuRegisterLo(fs_reg, registers_[rt_reg]);
2729 break;
2730 case rs_dmtc1:
2731 setFpuRegister(fs_reg, registers_[rt_reg]);
2732 break;
2733 case rs_mthc1:
2734 setFpuRegisterHi(fs_reg, registers_[rt_reg]);
2735 break;
2736 case rs_s:
2737 float f, ft_value, fs_value;
2738 uint32_t cc, fcsr_cc;
2739 int64_t i64;
2740 fs_value = getFpuRegisterFloat(fs_reg);
2741 ft_value = getFpuRegisterFloat(ft_reg);
2742 cc = instr->fcccValue();
2743 fcsr_cc = GetFCSRConditionBit(cc);
2744 switch (instr->functionFieldRaw()) {
2745 case ff_add_fmt:
2746 setFpuRegisterFloat(fd_reg, fs_value + ft_value);
2747 break;
2748 case ff_sub_fmt:
2749 setFpuRegisterFloat(fd_reg, fs_value - ft_value);
2750 break;
2751 case ff_mul_fmt:
2752 setFpuRegisterFloat(fd_reg, fs_value * ft_value);
2753 break;
2754 case ff_div_fmt:
2755 setFpuRegisterFloat(fd_reg, fs_value / ft_value);
2756 break;
2757 case ff_abs_fmt:
2758 setFpuRegisterFloat(fd_reg, fabsf(fs_value));
2759 break;
2760 case ff_mov_fmt:
2761 setFpuRegisterFloat(fd_reg, fs_value);
2762 break;
2763 case ff_neg_fmt:
2764 setFpuRegisterFloat(fd_reg, -fs_value);
2765 break;
2766 case ff_sqrt_fmt:
2767 setFpuRegisterFloat(fd_reg, sqrtf(fs_value));
2768 break;
2769 case ff_c_un_fmt:
2770 setFCSRBit(fcsr_cc, mozilla::IsNaN(fs_value) || mozilla::IsNaN(ft_value));
2771 break;
2772 case ff_c_eq_fmt:
2773 setFCSRBit(fcsr_cc, (fs_value == ft_value));
2774 break;
2775 case ff_c_ueq_fmt:
2776 setFCSRBit(fcsr_cc,
2777 (fs_value == ft_value) || (mozilla::IsNaN(fs_value) || mozilla::IsNaN(ft_value)));
2778 break;
2779 case ff_c_olt_fmt:
2780 setFCSRBit(fcsr_cc, (fs_value < ft_value));
2781 break;
2782 case ff_c_ult_fmt:
2783 setFCSRBit(fcsr_cc,
2784 (fs_value < ft_value) || (mozilla::IsNaN(fs_value) || mozilla::IsNaN(ft_value)));
2785 break;
2786 case ff_c_ole_fmt:
2787 setFCSRBit(fcsr_cc, (fs_value <= ft_value));
2788 break;
2789 case ff_c_ule_fmt:
2790 setFCSRBit(fcsr_cc,
2791 (fs_value <= ft_value) || (mozilla::IsNaN(fs_value) || mozilla::IsNaN(ft_value)));
2792 break;
2793 case ff_cvt_d_fmt:
2794 f = getFpuRegisterFloat(fs_reg);
2795 setFpuRegisterDouble(fd_reg, static_cast<double>(f));
2796 break;
2797 case ff_cvt_w_fmt: // Convert float to word.
2798 // Rounding modes are not yet supported.
2799 MOZ_ASSERT((FCSR_ & 3) == 0);
2800 // In rounding mode 0 it should behave like ROUND.
2801 case ff_round_w_fmt: { // Round double to word (round half to even).
2802 float rounded = std::floor(fs_value + 0.5);
2803 int32_t result = I32(rounded);
2804 if ((result & 1) != 0 && result - fs_value == 0.5) {
2805 // If the number is halfway between two integers,
2806 // round to the even one.
2807 result--;
2808 }
2809 setFpuRegisterLo(fd_reg, result);
2810 if (setFCSRRoundError(fs_value, rounded)) {
2811 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2812 }
2813 break;
2814 }
2815 case ff_trunc_w_fmt: { // Truncate float to word (round towards 0).
2816 float rounded = truncf(fs_value);
2817 int32_t result = I32(rounded);
2818 setFpuRegisterLo(fd_reg, result);
2819 if (setFCSRRoundError(fs_value, rounded)) {
2820 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2821 }
2822 break;
2823 }
2824 case ff_floor_w_fmt: { // Round float to word towards negative infinity.
2825 float rounded = std::floor(fs_value);
2826 int32_t result = I32(rounded);
2827 setFpuRegisterLo(fd_reg, result);
2828 if (setFCSRRoundError(fs_value, rounded)) {
2829 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2830 }
2831 break;
2832 }
2833 case ff_ceil_w_fmt: { // Round double to word towards positive infinity.
2834 float rounded = std::ceil(fs_value);
2835 int32_t result = I32(rounded);
2836 setFpuRegisterLo(fd_reg, result);
2837 if (setFCSRRoundError(fs_value, rounded)) {
2838 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2839 }
2840 break;
2841 }
2842 case ff_cvt_l_fmt: { // Mips64r2: Truncate float to 64-bit long-word.
2843 float rounded = truncf(fs_value);
2844 i64 = I64(rounded);
2845 setFpuRegister(fd_reg, i64);
2846 break;
2847 }
2848 case ff_round_l_fmt: { // Mips64r2 instruction.
2849 float rounded =
2850 fs_value > 0 ? std::floor(fs_value + 0.5) : std::ceil(fs_value - 0.5);
2851 i64 = I64(rounded);
2852 setFpuRegister(fd_reg, i64);
2853 break;
2854 }
2855 case ff_trunc_l_fmt: { // Mips64r2 instruction.
2856 float rounded = truncf(fs_value);
2857 i64 = I64(rounded);
2858 setFpuRegister(fd_reg, i64);
2859 break;
2860 }
2861 case ff_floor_l_fmt: // Mips64r2 instruction.
2862 i64 = I64(std::floor(fs_value));
2863 setFpuRegister(fd_reg, i64);
2864 break;
2865 case ff_ceil_l_fmt: // Mips64r2 instruction.
2866 i64 = I64(std::ceil(fs_value));
2867 setFpuRegister(fd_reg, i64);
2868 break;
2869 case ff_cvt_ps_s:
2870 case ff_c_f_fmt:
2871 MOZ_CRASH();
2872 break;
2873 default:
2874 MOZ_CRASH();
2875 }
2876 break;
2877 case rs_d:
2878 double dt_value, ds_value;
2879 ds_value = getFpuRegisterDouble(fs_reg);
2880 dt_value = getFpuRegisterDouble(ft_reg);
2881 cc = instr->fcccValue();
2882 fcsr_cc = GetFCSRConditionBit(cc);
2883 switch (instr->functionFieldRaw()) {
2884 case ff_add_fmt:
2885 setFpuRegisterDouble(fd_reg, ds_value + dt_value);
2886 break;
2887 case ff_sub_fmt:
2888 setFpuRegisterDouble(fd_reg, ds_value - dt_value);
2889 break;
2890 case ff_mul_fmt:
2891 setFpuRegisterDouble(fd_reg, ds_value * dt_value);
2892 break;
2893 case ff_div_fmt:
2894 setFpuRegisterDouble(fd_reg, ds_value / dt_value);
2895 break;
2896 case ff_abs_fmt:
2897 setFpuRegisterDouble(fd_reg, fabs(ds_value));
2898 break;
2899 case ff_mov_fmt:
2900 setFpuRegisterDouble(fd_reg, ds_value);
2901 break;
2902 case ff_neg_fmt:
2903 setFpuRegisterDouble(fd_reg, -ds_value);
2904 break;
2905 case ff_sqrt_fmt:
2906 setFpuRegisterDouble(fd_reg, sqrt(ds_value));
2907 break;
2908 case ff_c_un_fmt:
2909 setFCSRBit(fcsr_cc, mozilla::IsNaN(ds_value) || mozilla::IsNaN(dt_value));
2910 break;
2911 case ff_c_eq_fmt:
2912 setFCSRBit(fcsr_cc, (ds_value == dt_value));
2913 break;
2914 case ff_c_ueq_fmt:
2915 setFCSRBit(fcsr_cc,
2916 (ds_value == dt_value) || (mozilla::IsNaN(ds_value) || mozilla::IsNaN(dt_value)));
2917 break;
2918 case ff_c_olt_fmt:
2919 setFCSRBit(fcsr_cc, (ds_value < dt_value));
2920 break;
2921 case ff_c_ult_fmt:
2922 setFCSRBit(fcsr_cc,
2923 (ds_value < dt_value) || (mozilla::IsNaN(ds_value) || mozilla::IsNaN(dt_value)));
2924 break;
2925 case ff_c_ole_fmt:
2926 setFCSRBit(fcsr_cc, (ds_value <= dt_value));
2927 break;
2928 case ff_c_ule_fmt:
2929 setFCSRBit(fcsr_cc,
2930 (ds_value <= dt_value) || (mozilla::IsNaN(ds_value) || mozilla::IsNaN(dt_value)));
2931 break;
2932 case ff_cvt_w_fmt: // Convert double to word.
2933 // Rounding modes are not yet supported.
2934 MOZ_ASSERT((FCSR_ & 3) == 0);
2935 // In rounding mode 0 it should behave like ROUND.
2936 case ff_round_w_fmt: { // Round double to word (round half to even).
2937 double rounded = std::floor(ds_value + 0.5);
2938 int32_t result = I32(rounded);
2939 if ((result & 1) != 0 && result - ds_value == 0.5) {
2940 // If the number is halfway between two integers,
2941 // round to the even one.
2942 result--;
2943 }
2944 setFpuRegisterLo(fd_reg, result);
2945 if (setFCSRRoundError(ds_value, rounded))
2946 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2947 break;
2948 }
2949 case ff_trunc_w_fmt: { // Truncate double to word (round towards 0).
2950 double rounded = trunc(ds_value);
2951 int32_t result = I32(rounded);
2952 setFpuRegisterLo(fd_reg, result);
2953 if (setFCSRRoundError(ds_value, rounded))
2954 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2955 break;
2956 }
2957 case ff_floor_w_fmt: { // Round double to word towards negative infinity.
2958 double rounded = std::floor(ds_value);
2959 int32_t result = I32(rounded);
2960 setFpuRegisterLo(fd_reg, result);
2961 if (setFCSRRoundError(ds_value, rounded))
2962 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2963 break;
2964 }
2965 case ff_ceil_w_fmt: { // Round double to word towards positive infinity.
2966 double rounded = std::ceil(ds_value);
2967 int32_t result = I32(rounded);
2968 setFpuRegisterLo(fd_reg, result);
2969 if (setFCSRRoundError(ds_value, rounded))
2970 setFpuRegisterLo(fd_reg, kFPUInvalidResult);
2971 break;
2972 }
2973 case ff_cvt_s_fmt: // Convert double to float (single).
2974 setFpuRegisterFloat(fd_reg, static_cast<float>(ds_value));
2975 break;
2976 case ff_cvt_l_fmt: { // Mips64r2: Truncate double to 64-bit long-word.
2977 double rounded = trunc(ds_value);
2978 i64 = I64(rounded);
2979 setFpuRegister(fd_reg, i64);
2980 break;
2981 }
2982 case ff_trunc_l_fmt: { // Mips64r2 instruction.
2983 double rounded = trunc(ds_value);
2984 i64 = I64(rounded);
2985 setFpuRegister(fd_reg, i64);
2986 break;
2987 }
2988 case ff_round_l_fmt: { // Mips64r2 instruction.
2989 double rounded =
2990 ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
2991 i64 = I64(rounded);
2992 setFpuRegister(fd_reg, i64);
2993 break;
2994 }
2995 case ff_floor_l_fmt: // Mips64r2 instruction.
2996 i64 = I64(std::floor(ds_value));
2997 setFpuRegister(fd_reg, i64);
2998 break;
2999 case ff_ceil_l_fmt: // Mips64r2 instruction.
3000 i64 = I64(std::ceil(ds_value));
3001 setFpuRegister(fd_reg, i64);
3002 break;
3003 case ff_c_f_fmt:
3004 MOZ_CRASH();
3005 break;
3006 default:
3007 MOZ_CRASH();
3008 }
3009 break;
3010 case rs_w:
3011 switch (instr->functionFieldRaw()) {
3012 case ff_cvt_s_fmt: // Convert word to float (single).
3013 i64 = getFpuRegisterLo(fs_reg);
3014 setFpuRegisterFloat(fd_reg, static_cast<float>(i64));
3015 break;
3016 case ff_cvt_d_fmt: // Convert word to double.
3017 i64 = getFpuRegisterLo(fs_reg);
3018 setFpuRegisterDouble(fd_reg, static_cast<double>(i64));
3019 break;
3020 default:
3021 MOZ_CRASH();
3022 };
3023 break;
3024 case rs_l:
3025 switch (instr->functionFieldRaw()) {
3026 case ff_cvt_d_fmt: // Mips64r2 instruction.
3027 i64 = getFpuRegister(fs_reg);
3028 setFpuRegisterDouble(fd_reg, static_cast<double>(i64));
3029 break;
3030 case ff_cvt_s_fmt:
3031 MOZ_CRASH();
3032 break;
3033 default:
3034 MOZ_CRASH();
3035 }
3036 break;
3037 case rs_ps:
3038 break;
3039 default:
3040 MOZ_CRASH();
3041 };
3042 break;
3043 case op_cop1x:
3044 switch (instr->functionFieldRaw()) {
3045 case ff_madd_s:
3046 float fr, ft, fs;
3047 fr = getFpuRegisterFloat(fr_reg);
3048 fs = getFpuRegisterFloat(fs_reg);
3049 ft = getFpuRegisterFloat(ft_reg);
3050 setFpuRegisterFloat(fd_reg, fs * ft + fr);
3051 break;
3052 case ff_madd_d:
3053 double dr, dt, ds;
3054 dr = getFpuRegisterDouble(fr_reg);
3055 ds = getFpuRegisterDouble(fs_reg);
3056 dt = getFpuRegisterDouble(ft_reg);
3057 setFpuRegisterDouble(fd_reg, ds * dt + dr);
3058 break;
3059 default:
3060 MOZ_CRASH();
3061 };
3062 break;
3063 case op_special:
3064 switch (instr->functionFieldRaw()) {
3065 case ff_jr: {
3066 SimInstruction* branch_delay_instr = reinterpret_cast<SimInstruction*>(
3067 current_pc + SimInstruction::kInstrSize);
3068 branchDelayInstructionDecode(branch_delay_instr);
3069 set_pc(next_pc);
3070 pc_modified_ = true;
3071 break;
3072 }
3073 case ff_jalr: {
3074 SimInstruction* branch_delay_instr = reinterpret_cast<SimInstruction*>(
3075 current_pc + SimInstruction::kInstrSize);
3076 setRegister(return_addr_reg, current_pc + 2 * SimInstruction::kInstrSize);
3077 branchDelayInstructionDecode(branch_delay_instr);
3078 set_pc(next_pc);
3079 pc_modified_ = true;
3080 break;
3081 }
3082 // Instructions using HI and LO registers.
3083 case ff_mult:
3084 setRegister(LO, I32(i128hilo & 0xffffffff));
3085 setRegister(HI, I32(i128hilo >> 32));
3086 break;
3087 case ff_dmult:
3088 setRegister(LO, I64(i128hilo & 0xfffffffffffffffful));
3089 setRegister(HI, I64(i128hilo >> 64));
3090 break;
3091 case ff_multu:
3092 setRegister(LO, I32(u128hilo & 0xffffffff));
3093 setRegister(HI, I32(u128hilo >> 32));
3094 break;
3095 case ff_dmultu:
3096 setRegister(LO, I64(u128hilo & 0xfffffffffffffffful));
3097 setRegister(HI, I64(u128hilo >> 64));
3098 break;
3099 case ff_div:
3100 case ff_divu:
3101 // Divide by zero and overflow was not checked in the configuration
3102 // step - div and divu do not raise exceptions. On division by 0
3103 // the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
3104 // return INT_MIN which is what the hardware does.
3105 setRegister(LO, I32(i128hilo & 0xffffffff));
3106 setRegister(HI, I32(i128hilo >> 32));
3107 break;
3108 case ff_ddiv:
3109 case ff_ddivu:
3110 // Divide by zero and overflow was not checked in the configuration
3111 // step - div and divu do not raise exceptions. On division by 0
3112 // the result will be UNPREDICTABLE. On overflow (INT_MIN/-1),
3113 // return INT_MIN which is what the hardware does.
3114 setRegister(LO, I64(i128hilo & 0xfffffffffffffffful));
3115 setRegister(HI, I64(i128hilo >> 64));
3116 break;
3117 case ff_sync:
3118 break;
3119 // Break and trap instructions.
3120 case ff_break:
3121 case ff_tge:
3122 case ff_tgeu:
3123 case ff_tlt:
3124 case ff_tltu:
3125 case ff_teq:
3126 case ff_tne:
3127 if (do_interrupt) {
3128 softwareInterrupt(instr);
3129 }
3130 break;
3131 // Conditional moves.
3132 case ff_movn:
3133 if (rt)
3134 setRegister(rd_reg, rs);
3135 break;
3136 case ff_movci: {
3137 uint32_t cc = instr->fbccValue();
3138 uint32_t fcsr_cc = GetFCSRConditionBit(cc);
3139 if (instr->bit(16)) { // Read Tf bit.
3140 if (testFCSRBit(fcsr_cc))
3141 setRegister(rd_reg, rs);
3142 } else {
3143 if (!testFCSRBit(fcsr_cc))
3144 setRegister(rd_reg, rs);
3145 }
3146 break;
3147 }
3148 case ff_movz:
3149 if (!rt)
3150 setRegister(rd_reg, rs);
3151 break;
3152 default: // For other special opcodes we do the default operation.
3153 setRegister(rd_reg, alu_out);
3154 };
3155 break;
3156 case op_special2:
3157 switch (instr->functionFieldRaw()) {
3158 case ff_mul:
3159 setRegister(rd_reg, alu_out);
3160 // HI and LO are UNPREDICTABLE after the operation.
3161 setRegister(LO, Unpredictable);
3162 setRegister(HI, Unpredictable);
3163 break;
3164 default: // For other special2 opcodes we do the default operation.
3165 setRegister(rd_reg, alu_out);
3166 }
3167 break;
3168 case op_special3:
3169 switch (instr->functionFieldRaw()) {
3170 case ff_ins:
3171 case ff_dins:
3172 case ff_dinsm:
3173 case ff_dinsu:
3174 // Ins instr leaves result in Rt, rather than Rd.
3175 setRegister(rt_reg, alu_out);
3176 break;
3177 case ff_ext:
3178 case ff_dext:
3179 case ff_dextm:
3180 case ff_dextu:
3181 // Ext instr leaves result in Rt, rather than Rd.
3182 setRegister(rt_reg, alu_out);
3183 break;
3184 case ff_bshfl:
3185 setRegister(rd_reg, alu_out);
3186 break;
3187 default:
3188 MOZ_CRASH();
3189 };
3190 break;
3191 // Unimplemented opcodes raised an error in the configuration step before,
3192 // so we can use the default here to set the destination register in common
3193 // cases.
3194 default:
3195 setRegister(rd_reg, alu_out);
3196 };
3197 }
3198
3199 // Type 2: instructions using a 16 bits immediate. (e.g. addi, beq).
3200 void
decodeTypeImmediate(SimInstruction * instr)3201 Simulator::decodeTypeImmediate(SimInstruction* instr)
3202 {
3203 // Instruction fields.
3204 Opcode op = instr->opcodeFieldRaw();
3205 int64_t rs = getRegister(instr->rsValue());
3206 int32_t rt_reg = instr->rtValue(); // Destination register.
3207 int64_t rt = getRegister(rt_reg);
3208 int16_t imm16 = instr->imm16Value();
3209
3210 int32_t ft_reg = instr->ftValue(); // Destination register.
3211
3212 // Zero extended immediate.
3213 uint32_t oe_imm16 = 0xffff & imm16;
3214 // Sign extended immediate.
3215 int32_t se_imm16 = imm16;
3216
3217 // Get current pc.
3218 int64_t current_pc = get_pc();
3219 // Next pc.
3220 int64_t next_pc = bad_ra;
3221
3222 // Used for conditional branch instructions.
3223 bool do_branch = false;
3224 bool execute_branch_delay_instruction = false;
3225
3226 // Used for arithmetic instructions.
3227 int64_t alu_out = 0;
3228 // Floating point.
3229 double fp_out = 0.0;
3230 uint32_t cc, cc_value, fcsr_cc;
3231
3232 // Used for memory instructions.
3233 uint64_t addr = 0x0;
3234 // Value to be written in memory.
3235 uint64_t mem_value = 0x0;
3236 __int128 temp;
3237
3238 // ---------- Configuration (and execution for op_regimm).
3239 switch (op) {
3240 // ------------- op_cop1. Coprocessor instructions.
3241 case op_cop1:
3242 switch (instr->rsFieldRaw()) {
3243 case rs_bc1: // Branch on coprocessor condition.
3244 cc = instr->fbccValue();
3245 fcsr_cc = GetFCSRConditionBit(cc);
3246 cc_value = testFCSRBit(fcsr_cc);
3247 do_branch = (instr->fbtrueValue()) ? cc_value : !cc_value;
3248 execute_branch_delay_instruction = true;
3249 // Set next_pc.
3250 if (do_branch)
3251 next_pc = current_pc + (imm16 << 2) + SimInstruction::kInstrSize;
3252 else
3253 next_pc = current_pc + kBranchReturnOffset;
3254 break;
3255 default:
3256 MOZ_CRASH();
3257 };
3258 break;
3259 // ------------- op_regimm class.
3260 case op_regimm:
3261 switch (instr->rtFieldRaw()) {
3262 case rt_bltz:
3263 do_branch = (rs < 0);
3264 break;
3265 case rt_bltzal:
3266 do_branch = rs < 0;
3267 break;
3268 case rt_bgez:
3269 do_branch = rs >= 0;
3270 break;
3271 case rt_bgezal:
3272 do_branch = rs >= 0;
3273 break;
3274 default:
3275 MOZ_CRASH();
3276 };
3277 switch (instr->rtFieldRaw()) {
3278 case rt_bltz:
3279 case rt_bltzal:
3280 case rt_bgez:
3281 case rt_bgezal:
3282 // Branch instructions common part.
3283 execute_branch_delay_instruction = true;
3284 // Set next_pc.
3285 if (do_branch) {
3286 next_pc = current_pc + (imm16 << 2) + SimInstruction::kInstrSize;
3287 if (instr->isLinkingInstruction())
3288 setRegister(31, current_pc + kBranchReturnOffset);
3289 } else {
3290 next_pc = current_pc + kBranchReturnOffset;
3291 }
3292 default:
3293 break;
3294 };
3295 break; // case op_regimm.
3296 // ------------- Branch instructions.
3297 // When comparing to zero, the encoding of rt field is always 0, so we don't
3298 // need to replace rt with zero.
3299 case op_beq:
3300 do_branch = (rs == rt);
3301 break;
3302 case op_bne:
3303 do_branch = rs != rt;
3304 break;
3305 case op_blez:
3306 do_branch = rs <= 0;
3307 break;
3308 case op_bgtz:
3309 do_branch = rs > 0;
3310 break;
3311 // ------------- Arithmetic instructions.
3312 case op_addi:
3313 alu_out = I32(rs) + se_imm16;
3314 if ((alu_out << 32) != (alu_out << 31))
3315 exceptions[kIntegerOverflow] = 1;
3316 alu_out = I32(alu_out);
3317 break;
3318 case op_daddi:
3319 temp = alu_out = rs + se_imm16;
3320 if ((temp << 64) != (temp << 63))
3321 exceptions[kIntegerOverflow] = 1;
3322 alu_out = I64(temp);
3323 break;
3324 case op_addiu:
3325 alu_out = I32(I32(rs) + se_imm16);
3326 break;
3327 case op_daddiu:
3328 alu_out = rs + se_imm16;
3329 break;
3330 case op_slti:
3331 alu_out = (rs < se_imm16) ? 1 : 0;
3332 break;
3333 case op_sltiu:
3334 alu_out = (U64(rs) < U64(se_imm16)) ? 1 : 0;
3335 break;
3336 case op_andi:
3337 alu_out = rs & oe_imm16;
3338 break;
3339 case op_ori:
3340 alu_out = rs | oe_imm16;
3341 break;
3342 case op_xori:
3343 alu_out = rs ^ oe_imm16;
3344 break;
3345 case op_lui:
3346 alu_out = (se_imm16 << 16);
3347 break;
3348 // ------------- Memory instructions.
3349 case op_lbu:
3350 addr = rs + se_imm16;
3351 alu_out = readBU(addr, instr);
3352 break;
3353 case op_lb:
3354 addr = rs + se_imm16;
3355 alu_out = readB(addr, instr);
3356 break;
3357 case op_lhu:
3358 addr = rs + se_imm16;
3359 alu_out = readHU(addr, instr);
3360 break;
3361 case op_lh:
3362 addr = rs + se_imm16;
3363 alu_out = readH(addr, instr);
3364 break;
3365 case op_lwu:
3366 addr = rs + se_imm16;
3367 alu_out = readWU(addr, instr);
3368 break;
3369 case op_lw:
3370 addr = rs + se_imm16;
3371 alu_out = readW(addr, instr);
3372 break;
3373 case op_lwl: {
3374 // al_offset is offset of the effective address within an aligned word.
3375 uint8_t al_offset = (rs + se_imm16) & 3;
3376 uint8_t byte_shift = 3 - al_offset;
3377 uint32_t mask = (1 << byte_shift * 8) - 1;
3378 addr = rs + se_imm16 - al_offset;
3379 alu_out = readW(addr, instr);
3380 alu_out <<= byte_shift * 8;
3381 alu_out |= rt & mask;
3382 break;
3383 }
3384 case op_lwr: {
3385 // al_offset is offset of the effective address within an aligned word.
3386 uint8_t al_offset = (rs + se_imm16) & 3;
3387 uint8_t byte_shift = 3 - al_offset;
3388 uint32_t mask = al_offset ? (~0 << (byte_shift + 1) * 8) : 0;
3389 addr = rs + se_imm16 - al_offset;
3390 alu_out = readW(addr, instr);
3391 alu_out = U32(alu_out) >> al_offset * 8;
3392 alu_out |= rt & mask;
3393 break;
3394 }
3395 case op_ll:
3396 addr = rs + se_imm16;
3397 alu_out = readW(addr, instr);
3398 break;
3399 case op_ld:
3400 addr = rs + se_imm16;
3401 alu_out = readDW(addr, instr);
3402 break;
3403 case op_ldl: {
3404 // al_offset is offset of the effective address within an aligned word.
3405 uint8_t al_offset = (rs + se_imm16) & 7;
3406 uint8_t byte_shift = 7 - al_offset;
3407 uint64_t mask = (1ul << byte_shift * 8) - 1;
3408 addr = rs + se_imm16 - al_offset;
3409 alu_out = readDW(addr, instr);
3410 alu_out <<= byte_shift * 8;
3411 alu_out |= rt & mask;
3412 break;
3413 }
3414 case op_ldr: {
3415 // al_offset is offset of the effective address within an aligned word.
3416 uint8_t al_offset = (rs + se_imm16) & 7;
3417 uint8_t byte_shift = 7 - al_offset;
3418 uint64_t mask = al_offset ? (~0ul << (byte_shift + 1) * 8) : 0;
3419 addr = rs + se_imm16 - al_offset;
3420 alu_out = readDW(addr, instr);
3421 alu_out = U64(alu_out) >> al_offset * 8;
3422 alu_out |= rt & mask;
3423 break;
3424 }
3425 case op_sb:
3426 addr = rs + se_imm16;
3427 break;
3428 case op_sh:
3429 addr = rs + se_imm16;
3430 break;
3431 case op_sw:
3432 addr = rs + se_imm16;
3433 break;
3434 case op_swl: {
3435 uint8_t al_offset = (rs + se_imm16) & 3;
3436 uint8_t byte_shift = 3 - al_offset;
3437 uint32_t mask = byte_shift ? (~0 << (al_offset + 1) * 8) : 0;
3438 addr = rs + se_imm16 - al_offset;
3439 mem_value = readW(addr, instr) & mask;
3440 mem_value |= U32(rt) >> byte_shift * 8;
3441 break;
3442 }
3443 case op_swr: {
3444 uint8_t al_offset = (rs + se_imm16) & 3;
3445 uint32_t mask = (1 << al_offset * 8) - 1;
3446 addr = rs + se_imm16 - al_offset;
3447 mem_value = readW(addr, instr);
3448 mem_value = (rt << al_offset * 8) | (mem_value & mask);
3449 break;
3450 }
3451 case op_sc:
3452 addr = rs + se_imm16;
3453 break;
3454 case op_sd:
3455 addr = rs + se_imm16;
3456 break;
3457 case op_sdl: {
3458 uint8_t al_offset = (rs + se_imm16) & 7;
3459 uint8_t byte_shift = 7 - al_offset;
3460 uint64_t mask = byte_shift ? (~0ul << (al_offset + 1) * 8) : 0;
3461 addr = rs + se_imm16 - al_offset;
3462 mem_value = readW(addr, instr) & mask;
3463 mem_value |= U64(rt) >> byte_shift * 8;
3464 break;
3465 }
3466 case op_sdr: {
3467 uint8_t al_offset = (rs + se_imm16) & 7;
3468 uint64_t mask = (1ul << al_offset * 8) - 1;
3469 addr = rs + se_imm16 - al_offset;
3470 mem_value = readW(addr, instr);
3471 mem_value = (rt << al_offset * 8) | (mem_value & mask);
3472 break;
3473 }
3474 case op_lwc1:
3475 addr = rs + se_imm16;
3476 alu_out = readW(addr, instr);
3477 break;
3478 case op_ldc1:
3479 addr = rs + se_imm16;
3480 fp_out = readD(addr, instr);
3481 break;
3482 case op_swc1:
3483 case op_sdc1:
3484 addr = rs + se_imm16;
3485 break;
3486 default:
3487 MOZ_CRASH();
3488 };
3489
3490 // ---------- Raise exceptions triggered.
3491 signalExceptions();
3492
3493 // ---------- Execution.
3494 switch (op) {
3495 // ------------- Branch instructions.
3496 case op_beq:
3497 case op_bne:
3498 case op_blez:
3499 case op_bgtz:
3500 // Branch instructions common part.
3501 execute_branch_delay_instruction = true;
3502 // Set next_pc.
3503 if (do_branch) {
3504 next_pc = current_pc + (imm16 << 2) + SimInstruction::kInstrSize;
3505 if (instr->isLinkingInstruction()) {
3506 setRegister(31, current_pc + 2 * SimInstruction::kInstrSize);
3507 }
3508 } else {
3509 next_pc = current_pc + 2 * SimInstruction::kInstrSize;
3510 }
3511 break;
3512 // ------------- Arithmetic instructions.
3513 case op_addi:
3514 case op_daddi:
3515 case op_addiu:
3516 case op_daddiu:
3517 case op_slti:
3518 case op_sltiu:
3519 case op_andi:
3520 case op_ori:
3521 case op_xori:
3522 case op_lui:
3523 setRegister(rt_reg, alu_out);
3524 break;
3525 // ------------- Memory instructions.
3526 case op_lbu:
3527 case op_lb:
3528 case op_lhu:
3529 case op_lh:
3530 case op_lwu:
3531 case op_lw:
3532 case op_lwl:
3533 case op_lwr:
3534 case op_ll:
3535 case op_ld:
3536 case op_ldl:
3537 case op_ldr:
3538 setRegister(rt_reg, alu_out);
3539 break;
3540 case op_sb:
3541 writeB(addr, I8(rt), instr);
3542 break;
3543 case op_sh:
3544 writeH(addr, U16(rt), instr);
3545 break;
3546 case op_sw:
3547 writeW(addr, I32(rt), instr);
3548 break;
3549 case op_swl:
3550 writeW(addr, I32(mem_value), instr);
3551 break;
3552 case op_swr:
3553 writeW(addr, I32(mem_value), instr);
3554 break;
3555 case op_sc:
3556 writeW(addr, I32(rt), instr);
3557 setRegister(rt_reg, 1);
3558 break;
3559 case op_sd:
3560 writeDW(addr, rt, instr);
3561 break;
3562 case op_sdl:
3563 writeDW(addr, mem_value, instr);
3564 break;
3565 case op_sdr:
3566 writeDW(addr, mem_value, instr);
3567 break;
3568 case op_lwc1:
3569 setFpuRegisterLo(ft_reg, alu_out);
3570 break;
3571 case op_ldc1:
3572 setFpuRegisterDouble(ft_reg, fp_out);
3573 break;
3574 case op_swc1:
3575 writeW(addr, getFpuRegisterLo(ft_reg), instr);
3576 break;
3577 case op_sdc1:
3578 writeD(addr, getFpuRegisterDouble(ft_reg), instr);
3579 break;
3580 default:
3581 break;
3582 };
3583
3584
3585 if (execute_branch_delay_instruction) {
3586 // Execute branch delay slot
3587 // We don't check for end_sim_pc. First it should not be met as the current
3588 // pc is valid. Secondly a jump should always execute its branch delay slot.
3589 SimInstruction* branch_delay_instr =
3590 reinterpret_cast<SimInstruction*>(current_pc + SimInstruction::kInstrSize);
3591 branchDelayInstructionDecode(branch_delay_instr);
3592 }
3593
3594 // If needed update pc after the branch delay execution.
3595 if (next_pc != bad_ra)
3596 set_pc(next_pc);
3597 }
3598
3599 // Type 3: instructions using a 26 bits immediate. (e.g. j, jal).
3600 void
decodeTypeJump(SimInstruction * instr)3601 Simulator::decodeTypeJump(SimInstruction* instr)
3602 {
3603 // Get current pc.
3604 int64_t current_pc = get_pc();
3605 // Get unchanged bits of pc.
3606 int64_t pc_high_bits = current_pc & 0xfffffffff0000000ul;
3607 // Next pc.
3608 int64_t next_pc = pc_high_bits | (instr->imm26Value() << 2);
3609
3610 // Execute branch delay slot.
3611 // We don't check for end_sim_pc. First it should not be met as the current pc
3612 // is valid. Secondly a jump should always execute its branch delay slot.
3613 SimInstruction* branch_delay_instr =
3614 reinterpret_cast<SimInstruction*>(current_pc + SimInstruction::kInstrSize);
3615 branchDelayInstructionDecode(branch_delay_instr);
3616
3617 // Update pc and ra if necessary.
3618 // Do this after the branch delay execution.
3619 if (instr->isLinkingInstruction())
3620 setRegister(31, current_pc + 2 * SimInstruction::kInstrSize);
3621 set_pc(next_pc);
3622 pc_modified_ = true;
3623 }
3624
3625 // Executes the current instruction.
3626 void
instructionDecode(SimInstruction * instr)3627 Simulator::instructionDecode(SimInstruction* instr)
3628 {
3629 if (Simulator::ICacheCheckingEnabled) {
3630 AutoLockSimulatorCache als(this);
3631 CheckICacheLocked(icache(), instr);
3632 }
3633 pc_modified_ = false;
3634
3635 switch (instr->instructionType()) {
3636 case SimInstruction::kRegisterType:
3637 decodeTypeRegister(instr);
3638 break;
3639 case SimInstruction::kImmediateType:
3640 decodeTypeImmediate(instr);
3641 break;
3642 case SimInstruction::kJumpType:
3643 decodeTypeJump(instr);
3644 break;
3645 default:
3646 UNSUPPORTED();
3647 }
3648 if (!pc_modified_)
3649 setRegister(pc, reinterpret_cast<int64_t>(instr) + SimInstruction::kInstrSize);
3650 }
3651
3652 void
branchDelayInstructionDecode(SimInstruction * instr)3653 Simulator::branchDelayInstructionDecode(SimInstruction* instr)
3654 {
3655 if (single_stepping_)
3656 single_step_callback_(single_step_callback_arg_, this, (void*)instr);
3657
3658 if (instr->instructionBits() == NopInst) {
3659 // Short-cut generic nop instructions. They are always valid and they
3660 // never change the simulator state.
3661 return;
3662 }
3663
3664 if (instr->isForbiddenInBranchDelay()) {
3665 MOZ_CRASH("Eror:Unexpected opcode in a branch delay slot.");
3666 }
3667 instructionDecode(instr);
3668 }
3669
3670 void
enable_single_stepping(SingleStepCallback cb,void * arg)3671 Simulator::enable_single_stepping(SingleStepCallback cb, void* arg)
3672 {
3673 single_stepping_ = true;
3674 single_step_callback_ = cb;
3675 single_step_callback_arg_ = arg;
3676 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
3677 }
3678
3679 void
disable_single_stepping()3680 Simulator::disable_single_stepping()
3681 {
3682 if (!single_stepping_)
3683 return;
3684 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc());
3685 single_stepping_ = false;
3686 single_step_callback_ = nullptr;
3687 single_step_callback_arg_ = nullptr;
3688 }
3689
3690 template<bool enableStopSimAt>
3691 void
execute()3692 Simulator::execute()
3693 {
3694 if (single_stepping_)
3695 single_step_callback_(single_step_callback_arg_, this, nullptr);
3696
3697 // Get the PC to simulate. Cannot use the accessor here as we need the
3698 // raw PC value and not the one used as input to arithmetic instructions.
3699 int64_t program_counter = get_pc();
3700 AsmJSActivation* activation = TlsPerThreadData.get()->runtimeFromMainThread()->asmJSActivationStack();
3701
3702 while (program_counter != end_sim_pc) {
3703 if (enableStopSimAt && (icount_ == Simulator::StopSimAt)) {
3704 MipsDebugger dbg(this);
3705 dbg.debug();
3706 } else {
3707 if (single_stepping_)
3708 single_step_callback_(single_step_callback_arg_, this, (void*)program_counter);
3709 SimInstruction* instr = reinterpret_cast<SimInstruction *>(program_counter);
3710 instructionDecode(instr);
3711 icount_++;
3712
3713 int64_t rpc = resume_pc_;
3714 if (MOZ_UNLIKELY(rpc != 0)) {
3715 // AsmJS signal handler ran and we have to adjust the pc.
3716 activation->setResumePC((void*)get_pc());
3717 set_pc(rpc);
3718 resume_pc_ = 0;
3719 }
3720 }
3721 program_counter = get_pc();
3722 }
3723
3724 if (single_stepping_)
3725 single_step_callback_(single_step_callback_arg_, this, nullptr);
3726 }
3727
3728 void
callInternal(uint8_t * entry)3729 Simulator::callInternal(uint8_t* entry)
3730 {
3731 // Prepare to execute the code at entry.
3732 setRegister(pc, reinterpret_cast<int64_t>(entry));
3733 // Put down marker for end of simulation. The simulator will stop simulation
3734 // when the PC reaches this value. By saving the "end simulation" value into
3735 // the LR the simulation stops when returning to this call point.
3736 setRegister(ra, end_sim_pc);
3737
3738 // Remember the values of callee-saved registers.
3739 // The code below assumes that r9 is not used as sb (static base) in
3740 // simulator code and therefore is regarded as a callee-saved register.
3741 int64_t s0_val = getRegister(s0);
3742 int64_t s1_val = getRegister(s1);
3743 int64_t s2_val = getRegister(s2);
3744 int64_t s3_val = getRegister(s3);
3745 int64_t s4_val = getRegister(s4);
3746 int64_t s5_val = getRegister(s5);
3747 int64_t s6_val = getRegister(s6);
3748 int64_t s7_val = getRegister(s7);
3749 int64_t gp_val = getRegister(gp);
3750 int64_t sp_val = getRegister(sp);
3751 int64_t fp_val = getRegister(fp);
3752
3753 // Set up the callee-saved registers with a known value. To be able to check
3754 // that they are preserved properly across JS execution.
3755 int64_t callee_saved_value = icount_;
3756 setRegister(s0, callee_saved_value);
3757 setRegister(s1, callee_saved_value);
3758 setRegister(s2, callee_saved_value);
3759 setRegister(s3, callee_saved_value);
3760 setRegister(s4, callee_saved_value);
3761 setRegister(s5, callee_saved_value);
3762 setRegister(s6, callee_saved_value);
3763 setRegister(s7, callee_saved_value);
3764 setRegister(gp, callee_saved_value);
3765 setRegister(fp, callee_saved_value);
3766
3767 // Start the simulation.
3768 if (Simulator::StopSimAt != -1)
3769 execute<true>();
3770 else
3771 execute<false>();
3772
3773 // Check that the callee-saved registers have been preserved.
3774 MOZ_ASSERT(callee_saved_value == getRegister(s0));
3775 MOZ_ASSERT(callee_saved_value == getRegister(s1));
3776 MOZ_ASSERT(callee_saved_value == getRegister(s2));
3777 MOZ_ASSERT(callee_saved_value == getRegister(s3));
3778 MOZ_ASSERT(callee_saved_value == getRegister(s4));
3779 MOZ_ASSERT(callee_saved_value == getRegister(s5));
3780 MOZ_ASSERT(callee_saved_value == getRegister(s6));
3781 MOZ_ASSERT(callee_saved_value == getRegister(s7));
3782 MOZ_ASSERT(callee_saved_value == getRegister(gp));
3783 MOZ_ASSERT(callee_saved_value == getRegister(fp));
3784
3785 // Restore callee-saved registers with the original value.
3786 setRegister(s0, s0_val);
3787 setRegister(s1, s1_val);
3788 setRegister(s2, s2_val);
3789 setRegister(s3, s3_val);
3790 setRegister(s4, s4_val);
3791 setRegister(s5, s5_val);
3792 setRegister(s6, s6_val);
3793 setRegister(s7, s7_val);
3794 setRegister(gp, gp_val);
3795 setRegister(sp, sp_val);
3796 setRegister(fp, fp_val);
3797 }
3798
3799 int64_t
call(uint8_t * entry,int argument_count,...)3800 Simulator::call(uint8_t* entry, int argument_count, ...)
3801 {
3802 va_list parameters;
3803 va_start(parameters, argument_count);
3804
3805 int64_t original_stack = getRegister(sp);
3806 // Compute position of stack on entry to generated code.
3807 int64_t entry_stack = original_stack;
3808 if (argument_count > kCArgSlotCount)
3809 entry_stack = entry_stack - argument_count * sizeof(int64_t);
3810 else
3811 entry_stack = entry_stack - kCArgsSlotsSize;
3812
3813 entry_stack &= ~U64(ABIStackAlignment - 1);
3814
3815 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
3816
3817 // Setup the arguments.
3818 for (int i = 0; i < argument_count; i++) {
3819 js::jit::Register argReg;
3820 if (GetIntArgReg(i, &argReg))
3821 setRegister(argReg.code(), va_arg(parameters, int64_t));
3822 else
3823 stack_argument[i] = va_arg(parameters, int64_t);
3824 }
3825
3826 va_end(parameters);
3827 setRegister(sp, entry_stack);
3828
3829 callInternal(entry);
3830
3831 // Pop stack passed arguments.
3832 MOZ_ASSERT(entry_stack == getRegister(sp));
3833 setRegister(sp, original_stack);
3834
3835 int64_t result = getRegister(v0);
3836 return result;
3837 }
3838
3839 uintptr_t
pushAddress(uintptr_t address)3840 Simulator::pushAddress(uintptr_t address)
3841 {
3842 int new_sp = getRegister(sp) - sizeof(uintptr_t);
3843 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
3844 *stack_slot = address;
3845 setRegister(sp, new_sp);
3846 return new_sp;
3847 }
3848
3849 uintptr_t
popAddress()3850 Simulator::popAddress()
3851 {
3852 int current_sp = getRegister(sp);
3853 uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
3854 uintptr_t address = *stack_slot;
3855 setRegister(sp, current_sp + sizeof(uintptr_t));
3856 return address;
3857 }
3858
3859 } // namespace jit
3860 } // namespace js
3861
3862 js::jit::Simulator*
simulator() const3863 JSRuntime::simulator() const
3864 {
3865 return simulator_;
3866 }
3867
3868 js::jit::Simulator*
simulator() const3869 js::PerThreadData::simulator() const
3870 {
3871 return runtime_->simulator();
3872 }
3873
3874 uintptr_t*
addressOfSimulatorStackLimit()3875 JSRuntime::addressOfSimulatorStackLimit()
3876 {
3877 return simulator_->addressOfStackLimit();
3878 }
3879