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