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