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