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