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