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, ®isters_[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