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