Simulator-arm.cpp (155608B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 // Copyright 2012 the V8 project authors. All rights reserved. 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following 11 // disclaimer in the documentation and/or other materials provided 12 // with the distribution. 13 // * Neither the name of Google Inc. nor the names of its 14 // contributors may be used to endorse or promote products derived 15 // from this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "jit/arm/Simulator-arm.h" 30 31 #include "mozilla/Casting.h" 32 #include "mozilla/DebugOnly.h" 33 #include "mozilla/EndianUtils.h" 34 #include "mozilla/Likely.h" 35 #include "mozilla/MathAlgorithms.h" 36 37 #include "jit/arm/Assembler-arm.h" 38 #include "jit/arm/disasm/Constants-arm.h" 39 #include "jit/AtomicOperations.h" 40 #include "js/UniquePtr.h" 41 #include "js/Utility.h" 42 #include "threading/LockGuard.h" 43 #include "vm/Float16.h" 44 #include "vm/JSContext.h" 45 #include "vm/Runtime.h" 46 #include "vm/SharedMem.h" 47 #include "wasm/WasmInstance.h" 48 #include "wasm/WasmSignalHandlers.h" 49 50 extern "C" { 51 52 MOZ_EXPORT int64_t __aeabi_idivmod(int x, int y) { 53 // Run-time ABI for the ARM architecture specifies that for |INT_MIN / -1| 54 // "an implementation is (sic) may return any convenient value, possibly the 55 // original numerator." 56 // 57 // |INT_MIN / -1| traps on x86, which isn't listed as an allowed behavior in 58 // the ARM docs, so instead follow LLVM and return the numerator. (And zero 59 // for the remainder.) 60 61 if (x == INT32_MIN && y == -1) { 62 return uint32_t(x); 63 } 64 65 uint32_t lo = uint32_t(x / y); 66 uint32_t hi = uint32_t(x % y); 67 return (int64_t(hi) << 32) | lo; 68 } 69 70 MOZ_EXPORT int64_t __aeabi_uidivmod(int x, int y) { 71 uint32_t lo = uint32_t(x) / uint32_t(y); 72 uint32_t hi = uint32_t(x) % uint32_t(y); 73 return (int64_t(hi) << 32) | lo; 74 } 75 } 76 77 namespace js { 78 namespace jit { 79 80 // For decoding load-exclusive and store-exclusive instructions. 81 namespace excl { 82 83 // Bit positions. 84 enum { 85 ExclusiveOpHi = 24, // Hi bit of opcode field 86 ExclusiveOpLo = 23, // Lo bit of opcode field 87 ExclusiveSizeHi = 22, // Hi bit of operand size field 88 ExclusiveSizeLo = 21, // Lo bit of operand size field 89 ExclusiveLoad = 20 // Bit indicating load 90 }; 91 92 // Opcode bits for exclusive instructions. 93 enum { ExclusiveOpcode = 3 }; 94 95 // Operand size, Bits(ExclusiveSizeHi,ExclusiveSizeLo). 96 enum { 97 ExclusiveWord = 0, 98 ExclusiveDouble = 1, 99 ExclusiveByte = 2, 100 ExclusiveHalf = 3 101 }; 102 103 } // namespace excl 104 105 // Load/store multiple addressing mode. 106 enum BlockAddrMode { 107 // Alias modes for comparison when writeback does not matter. 108 da_x = (0 | 0 | 0) << 21, // Decrement after. 109 ia_x = (0 | 4 | 0) << 21, // Increment after. 110 db_x = (8 | 0 | 0) << 21, // Decrement before. 111 ib_x = (8 | 4 | 0) << 21, // Increment before. 112 }; 113 114 // Type of VFP register. Determines register encoding. 115 enum VFPRegPrecision { kSinglePrecision = 0, kDoublePrecision = 1 }; 116 117 enum NeonListType { nlt_1 = 0x7, nlt_2 = 0xA, nlt_3 = 0x6, nlt_4 = 0x2 }; 118 119 // Supervisor Call (svc) specific support. 120 121 // Special Software Interrupt codes when used in the presence of the ARM 122 // simulator. 123 // svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for 124 // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature. 125 enum SoftwareInterruptCodes { 126 kCallRtRedirected = 0x10, // Transition to C code. 127 kBreakpoint = 0x20, // Breakpoint. 128 kStopCode = 1 << 23 // Stop. 129 }; 130 131 const uint32_t kStopCodeMask = kStopCode - 1; 132 const uint32_t kMaxStopCode = kStopCode - 1; 133 134 // ----------------------------------------------------------------------------- 135 // Instruction abstraction. 136 137 // The class Instruction enables access to individual fields defined in the ARM 138 // architecture instruction set encoding as described in figure A3-1. 139 // Note that the Assembler uses using Instr = int32_t. 140 // 141 // Example: Test whether the instruction at ptr does set the condition code 142 // bits. 143 // 144 // bool InstructionSetsConditionCodes(byte* ptr) { 145 // Instruction* instr = Instruction::At(ptr); 146 // int type = instr->TypeValue(); 147 // return ((type == 0) || (type == 1)) && instr->hasS(); 148 // } 149 // 150 class SimInstruction { 151 public: 152 enum { kInstrSize = 4, kPCReadOffset = 8 }; 153 154 // Get the raw instruction bits. 155 inline Instr instructionBits() const { 156 return *reinterpret_cast<const Instr*>(this); 157 } 158 159 // Set the raw instruction bits to value. 160 inline void setInstructionBits(Instr value) { 161 *reinterpret_cast<Instr*>(this) = value; 162 } 163 164 // Read one particular bit out of the instruction bits. 165 inline int bit(int nr) const { return (instructionBits() >> nr) & 1; } 166 167 // Read a bit field's value out of the instruction bits. 168 inline int bits(int hi, int lo) const { 169 return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1); 170 } 171 172 // Read a bit field out of the instruction bits. 173 inline int bitField(int hi, int lo) const { 174 return instructionBits() & (((2 << (hi - lo)) - 1) << lo); 175 } 176 177 // Accessors for the different named fields used in the ARM encoding. 178 // The naming of these accessor corresponds to figure A3-1. 179 // 180 // Two kind of accessors are declared: 181 // - <Name>Field() will return the raw field, i.e. the field's bits at their 182 // original place in the instruction encoding. 183 // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as 184 // 0xC0810002 conditionField(instr) will return 0xC0000000. 185 // - <Name>Value() will return the field value, shifted back to bit 0. 186 // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as 187 // 0xC0810002 conditionField(instr) will return 0xC. 188 189 // Generally applicable fields 190 inline Assembler::ARMCondition conditionField() const { 191 return static_cast<Assembler::ARMCondition>(bitField(31, 28)); 192 } 193 inline int typeValue() const { return bits(27, 25); } 194 inline int specialValue() const { return bits(27, 23); } 195 196 inline int rnValue() const { return bits(19, 16); } 197 inline int rdValue() const { return bits(15, 12); } 198 199 inline int coprocessorValue() const { return bits(11, 8); } 200 201 // Support for VFP. 202 // Vn(19-16) | Vd(15-12) | Vm(3-0) 203 inline int vnValue() const { return bits(19, 16); } 204 inline int vmValue() const { return bits(3, 0); } 205 inline int vdValue() const { return bits(15, 12); } 206 inline int nValue() const { return bit(7); } 207 inline int mValue() const { return bit(5); } 208 inline int dValue() const { return bit(22); } 209 inline int rtValue() const { return bits(15, 12); } 210 inline int pValue() const { return bit(24); } 211 inline int uValue() const { return bit(23); } 212 inline int opc1Value() const { return (bit(23) << 2) | bits(21, 20); } 213 inline int opc2Value() const { return bits(19, 16); } 214 inline int opc3Value() const { return bits(7, 6); } 215 inline int szValue() const { return bit(8); } 216 inline int VLValue() const { return bit(20); } 217 inline int VCValue() const { return bit(8); } 218 inline int VAValue() const { return bits(23, 21); } 219 inline int VBValue() const { return bits(6, 5); } 220 inline int VFPNRegValue(VFPRegPrecision pre) { 221 return VFPGlueRegValue(pre, 16, 7); 222 } 223 inline int VFPMRegValue(VFPRegPrecision pre) { 224 return VFPGlueRegValue(pre, 0, 5); 225 } 226 inline int VFPDRegValue(VFPRegPrecision pre) { 227 return VFPGlueRegValue(pre, 12, 22); 228 } 229 230 // Fields used in Data processing instructions. 231 inline int opcodeValue() const { return static_cast<ALUOp>(bits(24, 21)); } 232 inline ALUOp opcodeField() const { 233 return static_cast<ALUOp>(bitField(24, 21)); 234 } 235 inline int sValue() const { return bit(20); } 236 237 // With register. 238 inline int rmValue() const { return bits(3, 0); } 239 inline ShiftType shifttypeValue() const { 240 return static_cast<ShiftType>(bits(6, 5)); 241 } 242 inline int rsValue() const { return bits(11, 8); } 243 inline int shiftAmountValue() const { return bits(11, 7); } 244 245 // With immediate. 246 inline int rotateValue() const { return bits(11, 8); } 247 inline int immed8Value() const { return bits(7, 0); } 248 inline int immed4Value() const { return bits(19, 16); } 249 inline int immedMovwMovtValue() const { 250 return immed4Value() << 12 | offset12Value(); 251 } 252 253 // Fields used in Load/Store instructions. 254 inline int PUValue() const { return bits(24, 23); } 255 inline int PUField() const { return bitField(24, 23); } 256 inline int bValue() const { return bit(22); } 257 inline int wValue() const { return bit(21); } 258 inline int lValue() const { return bit(20); } 259 260 // With register uses same fields as Data processing instructions above with 261 // immediate. 262 inline int offset12Value() const { return bits(11, 0); } 263 264 // Multiple. 265 inline int rlistValue() const { return bits(15, 0); } 266 267 // Extra loads and stores. 268 inline int signValue() const { return bit(6); } 269 inline int hValue() const { return bit(5); } 270 inline int immedHValue() const { return bits(11, 8); } 271 inline int immedLValue() const { return bits(3, 0); } 272 273 // Fields used in Branch instructions. 274 inline int linkValue() const { return bit(24); } 275 inline int sImmed24Value() const { return ((instructionBits() << 8) >> 8); } 276 277 // Fields used in Software interrupt instructions. 278 inline SoftwareInterruptCodes svcValue() const { 279 return static_cast<SoftwareInterruptCodes>(bits(23, 0)); 280 } 281 282 // Test for special encodings of type 0 instructions (extra loads and 283 // stores, as well as multiplications). 284 inline bool isSpecialType0() const { return (bit(7) == 1) && (bit(4) == 1); } 285 286 // Test for miscellaneous instructions encodings of type 0 instructions. 287 inline bool isMiscType0() const { 288 return bit(24) == 1 && bit(23) == 0 && bit(20) == 0 && (bit(7) == 0); 289 } 290 291 // Test for a nop instruction, which falls under type 1. 292 inline bool isNopType1() const { return bits(24, 0) == 0x0120F000; } 293 294 // Test for a yield instruction, which falls under type 1. 295 inline bool isYieldType1() const { return bits(24, 0) == 0x0120F001; } 296 297 // Test for a nop instruction, which falls under type 1. 298 inline bool isCsdbType1() const { return bits(24, 0) == 0x0120F014; } 299 300 // Test for a stop instruction. 301 inline bool isStop() const { 302 return typeValue() == 7 && bit(24) == 1 && svcValue() >= kStopCode; 303 } 304 305 // Test for a udf instruction, which falls under type 3. 306 inline bool isUDF() const { 307 return (instructionBits() & 0xfff000f0) == 0xe7f000f0; 308 } 309 310 // Special accessors that test for existence of a value. 311 inline bool hasS() const { return sValue() == 1; } 312 inline bool hasB() const { return bValue() == 1; } 313 inline bool hasW() const { return wValue() == 1; } 314 inline bool hasL() const { return lValue() == 1; } 315 inline bool hasU() const { return uValue() == 1; } 316 inline bool hasSign() const { return signValue() == 1; } 317 inline bool hasH() const { return hValue() == 1; } 318 inline bool hasLink() const { return linkValue() == 1; } 319 320 // Decoding the double immediate in the vmov instruction. 321 double doubleImmedVmov() const; 322 // Decoding the float32 immediate in the vmov.f32 instruction. 323 float float32ImmedVmov() const; 324 325 private: 326 // Join split register codes, depending on single or double precision. 327 // four_bit is the position of the least-significant bit of the four 328 // bit specifier. one_bit is the position of the additional single bit 329 // specifier. 330 inline int VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) { 331 if (pre == kSinglePrecision) { 332 return (bits(four_bit + 3, four_bit) << 1) | bit(one_bit); 333 } 334 return (bit(one_bit) << 4) | bits(four_bit + 3, four_bit); 335 } 336 337 SimInstruction() = delete; 338 SimInstruction(const SimInstruction& other) = delete; 339 void operator=(const SimInstruction& other) = delete; 340 }; 341 342 double SimInstruction::doubleImmedVmov() const { 343 // Reconstruct a double from the immediate encoded in the vmov instruction. 344 // 345 // instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh] 346 // double: [aBbbbbbb,bbcdefgh,00000000,00000000, 347 // 00000000,00000000,00000000,00000000] 348 // 349 // where B = ~b. Only the high 16 bits are affected. 350 uint64_t high16; 351 high16 = (bits(17, 16) << 4) | bits(3, 0); // xxxxxxxx,xxcdefgh. 352 high16 |= (0xff * bit(18)) << 6; // xxbbbbbb,bbxxxxxx. 353 high16 |= (bit(18) ^ 1) << 14; // xBxxxxxx,xxxxxxxx. 354 high16 |= bit(19) << 15; // axxxxxxx,xxxxxxxx. 355 356 uint64_t imm = high16 << 48; 357 return mozilla::BitwiseCast<double>(imm); 358 } 359 360 float SimInstruction::float32ImmedVmov() const { 361 // Reconstruct a float32 from the immediate encoded in the vmov instruction. 362 // 363 // instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh] 364 // float32: [aBbbbbbc, defgh000, 00000000, 00000000] 365 // 366 // where B = ~b. Only the high 16 bits are affected. 367 uint32_t imm; 368 imm = (bits(17, 16) << 23) | (bits(3, 0) << 19); // xxxxxxxc,defgh000.0.0 369 imm |= (0x1f * bit(18)) << 25; // xxbbbbbx,xxxxxxxx.0.0 370 imm |= (bit(18) ^ 1) << 30; // xBxxxxxx,xxxxxxxx.0.0 371 imm |= bit(19) << 31; // axxxxxxx,xxxxxxxx.0.0 372 373 return mozilla::BitwiseCast<float>(imm); 374 } 375 376 class CachePage { 377 public: 378 static const int LINE_VALID = 0; 379 static const int LINE_INVALID = 1; 380 static const int kPageShift = 12; 381 static const int kPageSize = 1 << kPageShift; 382 static const int kPageMask = kPageSize - 1; 383 static const int kLineShift = 2; // The cache line is only 4 bytes right now. 384 static const int kLineLength = 1 << kLineShift; 385 static const int kLineMask = kLineLength - 1; 386 387 CachePage() { memset(&validity_map_, LINE_INVALID, sizeof(validity_map_)); } 388 char* validityByte(int offset) { 389 return &validity_map_[offset >> kLineShift]; 390 } 391 char* cachedData(int offset) { return &data_[offset]; } 392 393 private: 394 char data_[kPageSize]; // The cached data. 395 static const int kValidityMapSize = kPageSize >> kLineShift; 396 char validity_map_[kValidityMapSize]; // One byte per line. 397 }; 398 399 // Protects the icache() and redirection() properties of the 400 // Simulator. 401 class AutoLockSimulatorCache : public LockGuard<Mutex> { 402 using Base = LockGuard<Mutex>; 403 404 public: 405 explicit AutoLockSimulatorCache() 406 : Base(SimulatorProcess::singleton_->cacheLock_) {} 407 }; 408 409 mozilla::Atomic<size_t, mozilla::ReleaseAcquire> 410 SimulatorProcess::ICacheCheckingDisableCount( 411 1); // Checking is disabled by default. 412 SimulatorProcess* SimulatorProcess::singleton_ = nullptr; 413 414 int64_t Simulator::StopSimAt = -1L; 415 416 Simulator* Simulator::Create() { 417 auto sim = MakeUnique<Simulator>(); 418 if (!sim) { 419 return nullptr; 420 } 421 422 if (!sim->init()) { 423 return nullptr; 424 } 425 426 char* stopAtStr = getenv("ARM_SIM_STOP_AT"); 427 int64_t stopAt; 428 if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) { 429 fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt); 430 Simulator::StopSimAt = stopAt; 431 } 432 433 return sim.release(); 434 } 435 436 void Simulator::Destroy(Simulator* sim) { js_delete(sim); } 437 438 void Simulator::disassemble(SimInstruction* instr, size_t n) { 439 #ifdef JS_DISASM_ARM 440 disasm::NameConverter converter; 441 disasm::Disassembler dasm(converter); 442 disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer; 443 while (n-- > 0) { 444 dasm.InstructionDecode(buffer, reinterpret_cast<uint8_t*>(instr)); 445 fprintf(stderr, " 0x%08x %s\n", uint32_t(instr), buffer.start()); 446 instr = reinterpret_cast<SimInstruction*>( 447 reinterpret_cast<uint8_t*>(instr) + 4); 448 } 449 #endif 450 } 451 452 void Simulator::disasm(SimInstruction* instr) { disassemble(instr, 1); } 453 454 void Simulator::disasm(SimInstruction* instr, size_t n) { 455 disassemble(instr, n); 456 } 457 458 void Simulator::disasm(SimInstruction* instr, size_t m, size_t n) { 459 disassemble(reinterpret_cast<SimInstruction*>( 460 reinterpret_cast<uint8_t*>(instr) - m * 4), 461 n); 462 } 463 464 // The ArmDebugger class is used by the simulator while debugging simulated ARM 465 // code. 466 class ArmDebugger { 467 public: 468 explicit ArmDebugger(Simulator* sim) : sim_(sim) {} 469 470 void stop(SimInstruction* instr); 471 void debug(); 472 473 private: 474 static const Instr kBreakpointInstr = 475 (Assembler::AL | (7 * (1 << 25)) | (1 * (1 << 24)) | kBreakpoint); 476 static const Instr kNopInstr = (Assembler::AL | (13 * (1 << 21))); 477 478 Simulator* sim_; 479 480 int32_t getRegisterValue(int regnum); 481 double getRegisterPairDoubleValue(int regnum); 482 void getVFPDoubleRegisterValue(int regnum, double* value); 483 bool getValue(const char* desc, int32_t* value); 484 bool getVFPDoubleValue(const char* desc, double* value); 485 486 // Set or delete a breakpoint. Returns true if successful. 487 bool setBreakpoint(SimInstruction* breakpc); 488 bool deleteBreakpoint(SimInstruction* breakpc); 489 490 // Undo and redo all breakpoints. This is needed to bracket disassembly and 491 // execution to skip past breakpoints when run from the debugger. 492 void undoBreakpoints(); 493 void redoBreakpoints(); 494 }; 495 496 void ArmDebugger::stop(SimInstruction* instr) { 497 // Get the stop code. 498 uint32_t code = instr->svcValue() & kStopCodeMask; 499 // Retrieve the encoded address, which comes just after this stop. 500 char* msg = 501 *reinterpret_cast<char**>(sim_->get_pc() + SimInstruction::kInstrSize); 502 // Update this stop description. 503 if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) { 504 sim_->watched_stops_[code].desc = msg; 505 } 506 // Print the stop message and code if it is not the default code. 507 if (code != kMaxStopCode) { 508 printf("Simulator hit stop %u: %s\n", code, msg); 509 } else { 510 printf("Simulator hit %s\n", msg); 511 } 512 sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize); 513 debug(); 514 } 515 516 int32_t ArmDebugger::getRegisterValue(int regnum) { 517 if (regnum == Registers::pc) { 518 return sim_->get_pc(); 519 } 520 return sim_->get_register(regnum); 521 } 522 523 double ArmDebugger::getRegisterPairDoubleValue(int regnum) { 524 return sim_->get_double_from_register_pair(regnum); 525 } 526 527 void ArmDebugger::getVFPDoubleRegisterValue(int regnum, double* out) { 528 sim_->get_double_from_d_register(regnum, out); 529 } 530 531 bool ArmDebugger::getValue(const char* desc, int32_t* value) { 532 Register reg = Register::FromName(desc); 533 if (reg != InvalidReg) { 534 *value = getRegisterValue(reg.code()); 535 return true; 536 } 537 if (strncmp(desc, "0x", 2) == 0) { 538 return sscanf(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1; 539 } 540 return sscanf(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1; 541 } 542 543 bool ArmDebugger::getVFPDoubleValue(const char* desc, double* value) { 544 FloatRegister reg = FloatRegister::FromCode(FloatRegister::FromName(desc)); 545 if (reg.isInvalid()) { 546 return false; 547 } 548 549 if (reg.isSingle()) { 550 float fval; 551 sim_->get_float_from_s_register(reg.id(), &fval); 552 *value = fval; 553 return true; 554 } 555 556 sim_->get_double_from_d_register(reg.id(), value); 557 return true; 558 } 559 560 bool ArmDebugger::setBreakpoint(SimInstruction* breakpc) { 561 // Check if a breakpoint can be set. If not return without any side-effects. 562 if (sim_->break_pc_) { 563 return false; 564 } 565 566 // Set the breakpoint. 567 sim_->break_pc_ = breakpc; 568 sim_->break_instr_ = breakpc->instructionBits(); 569 // Not setting the breakpoint instruction in the code itself. It will be set 570 // when the debugger shell continues. 571 return true; 572 } 573 574 bool ArmDebugger::deleteBreakpoint(SimInstruction* breakpc) { 575 if (sim_->break_pc_ != nullptr) { 576 sim_->break_pc_->setInstructionBits(sim_->break_instr_); 577 } 578 579 sim_->break_pc_ = nullptr; 580 sim_->break_instr_ = 0; 581 return true; 582 } 583 584 void ArmDebugger::undoBreakpoints() { 585 if (sim_->break_pc_) { 586 sim_->break_pc_->setInstructionBits(sim_->break_instr_); 587 } 588 } 589 590 void ArmDebugger::redoBreakpoints() { 591 if (sim_->break_pc_) { 592 sim_->break_pc_->setInstructionBits(kBreakpointInstr); 593 } 594 } 595 596 static char* ReadLine(const char* prompt) { 597 UniqueChars result; 598 char line_buf[256]; 599 int offset = 0; 600 bool keep_going = true; 601 fprintf(stdout, "%s", prompt); 602 fflush(stdout); 603 while (keep_going) { 604 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) { 605 // fgets got an error. Just give up. 606 return nullptr; 607 } 608 int len = strlen(line_buf); 609 if (len > 0 && line_buf[len - 1] == '\n') { 610 // Since we read a new line we are done reading the line. This will 611 // exit the loop after copying this buffer into the result. 612 keep_going = false; 613 } 614 if (!result) { 615 // Allocate the initial result and make room for the terminating 616 // '\0'. 617 result.reset(js_pod_malloc<char>(len + 1)); 618 if (!result) { 619 return nullptr; 620 } 621 } else { 622 // Allocate a new result with enough room for the new addition. 623 int new_len = offset + len + 1; 624 char* new_result = js_pod_malloc<char>(new_len); 625 if (!new_result) { 626 return nullptr; 627 } 628 // Copy the existing input into the new array and set the new 629 // array as the result. 630 memcpy(new_result, result.get(), offset * sizeof(char)); 631 result.reset(new_result); 632 } 633 // Copy the newly read line into the result. 634 memcpy(result.get() + offset, line_buf, len * sizeof(char)); 635 offset += len; 636 } 637 638 MOZ_ASSERT(result); 639 result[offset] = '\0'; 640 return result.release(); 641 } 642 643 void ArmDebugger::debug() { 644 intptr_t last_pc = -1; 645 bool done = false; 646 647 #define COMMAND_SIZE 63 648 #define ARG_SIZE 255 649 650 #define STR(a) #a 651 #define XSTR(a) STR(a) 652 653 char cmd[COMMAND_SIZE + 1]; 654 char arg1[ARG_SIZE + 1]; 655 char arg2[ARG_SIZE + 1]; 656 char* argv[3] = {cmd, arg1, arg2}; 657 658 // Make sure to have a proper terminating character if reaching the limit. 659 cmd[COMMAND_SIZE] = 0; 660 arg1[ARG_SIZE] = 0; 661 arg2[ARG_SIZE] = 0; 662 663 // Undo all set breakpoints while running in the debugger shell. This will 664 // make them invisible to all commands. 665 undoBreakpoints(); 666 667 #ifndef JS_DISASM_ARM 668 static bool disasm_warning_printed = false; 669 if (!disasm_warning_printed) { 670 printf( 671 " No ARM disassembler present. Enable JS_DISASM_ARM in " 672 "configure.in."); 673 disasm_warning_printed = true; 674 } 675 #endif 676 677 while (!done && !sim_->has_bad_pc()) { 678 if (last_pc != sim_->get_pc()) { 679 #ifdef JS_DISASM_ARM 680 disasm::NameConverter converter; 681 disasm::Disassembler dasm(converter); 682 disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer; 683 dasm.InstructionDecode(buffer, 684 reinterpret_cast<uint8_t*>(sim_->get_pc())); 685 printf(" 0x%08x %s\n", sim_->get_pc(), buffer.start()); 686 #endif 687 last_pc = sim_->get_pc(); 688 } 689 char* line = ReadLine("sim> "); 690 if (line == nullptr) { 691 break; 692 } else { 693 char* last_input = sim_->lastDebuggerInput(); 694 if (strcmp(line, "\n") == 0 && last_input != nullptr) { 695 line = last_input; 696 } else { 697 // Ownership is transferred to sim_; 698 sim_->setLastDebuggerInput(line); 699 } 700 701 // Use sscanf to parse the individual parts of the command line. At the 702 // moment no command expects more than two parameters. 703 int argc = sscanf(line, 704 "%" XSTR(COMMAND_SIZE) "s " 705 "%" XSTR(ARG_SIZE) "s " 706 "%" XSTR(ARG_SIZE) "s", 707 cmd, arg1, arg2); 708 if (argc < 0) { 709 continue; 710 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) { 711 sim_->instructionDecode( 712 reinterpret_cast<SimInstruction*>(sim_->get_pc())); 713 sim_->icount_++; 714 } else if ((strcmp(cmd, "skip") == 0)) { 715 sim_->set_pc(sim_->get_pc() + 4); 716 sim_->icount_++; 717 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) { 718 // Execute the one instruction we broke at with breakpoints 719 // disabled. 720 sim_->instructionDecode( 721 reinterpret_cast<SimInstruction*>(sim_->get_pc())); 722 sim_->icount_++; 723 // Leave the debugger shell. 724 done = true; 725 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) { 726 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) { 727 int32_t value; 728 double dvalue; 729 if (strcmp(arg1, "all") == 0) { 730 for (uint32_t i = 0; i < Registers::Total; i++) { 731 value = getRegisterValue(i); 732 printf("%3s: 0x%08x %10d", Registers::GetName(i), value, value); 733 if ((argc == 3 && strcmp(arg2, "fp") == 0) && i < 8 && 734 (i % 2) == 0) { 735 dvalue = getRegisterPairDoubleValue(i); 736 printf(" (%.16g)\n", dvalue); 737 } else { 738 printf("\n"); 739 } 740 } 741 for (uint32_t i = 0; i < FloatRegisters::TotalPhys; i++) { 742 getVFPDoubleRegisterValue(i, &dvalue); 743 uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue); 744 printf("%3s: %.16g 0x%08x %08x\n", 745 FloatRegister::FromCode(i).name(), dvalue, 746 static_cast<uint32_t>(as_words >> 32), 747 static_cast<uint32_t>(as_words & 0xffffffff)); 748 } 749 } else { 750 if (getValue(arg1, &value)) { 751 printf("%s: 0x%08x %d \n", arg1, value, value); 752 } else if (getVFPDoubleValue(arg1, &dvalue)) { 753 uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue); 754 printf("%s: %.16g 0x%08x %08x\n", arg1, dvalue, 755 static_cast<uint32_t>(as_words >> 32), 756 static_cast<uint32_t>(as_words & 0xffffffff)); 757 } else { 758 printf("%s unrecognized\n", arg1); 759 } 760 } 761 } else { 762 printf("print <register>\n"); 763 } 764 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) { 765 int32_t* cur = nullptr; 766 int32_t* end = nullptr; 767 int next_arg = 1; 768 769 if (strcmp(cmd, "stack") == 0) { 770 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp)); 771 } else { // "mem" 772 int32_t value; 773 if (!getValue(arg1, &value)) { 774 printf("%s unrecognized\n", arg1); 775 continue; 776 } 777 cur = reinterpret_cast<int32_t*>(value); 778 next_arg++; 779 } 780 781 int32_t words; 782 if (argc == next_arg) { 783 words = 10; 784 } else { 785 if (!getValue(argv[next_arg], &words)) { 786 words = 10; 787 } 788 } 789 end = cur + words; 790 791 while (cur < end) { 792 printf(" %p: 0x%08x %10d", cur, *cur, *cur); 793 printf("\n"); 794 cur++; 795 } 796 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) { 797 #ifdef JS_DISASM_ARM 798 uint8_t* prev = nullptr; 799 uint8_t* cur = nullptr; 800 uint8_t* end = nullptr; 801 802 if (argc == 1) { 803 cur = reinterpret_cast<uint8_t*>(sim_->get_pc()); 804 end = cur + (10 * SimInstruction::kInstrSize); 805 } else if (argc == 2) { 806 Register reg = Register::FromName(arg1); 807 if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) { 808 // The argument is an address or a register name. 809 int32_t value; 810 if (getValue(arg1, &value)) { 811 cur = reinterpret_cast<uint8_t*>(value); 812 // Disassemble 10 instructions at <arg1>. 813 end = cur + (10 * SimInstruction::kInstrSize); 814 } 815 } else { 816 // The argument is the number of instructions. 817 int32_t value; 818 if (getValue(arg1, &value)) { 819 cur = reinterpret_cast<uint8_t*>(sim_->get_pc()); 820 // Disassemble <arg1> instructions. 821 end = cur + (value * SimInstruction::kInstrSize); 822 } 823 } 824 } else { 825 int32_t value1; 826 int32_t value2; 827 if (getValue(arg1, &value1) && getValue(arg2, &value2)) { 828 cur = reinterpret_cast<uint8_t*>(value1); 829 end = cur + (value2 * SimInstruction::kInstrSize); 830 } 831 } 832 while (cur < end) { 833 disasm::NameConverter converter; 834 disasm::Disassembler dasm(converter); 835 disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer; 836 837 prev = cur; 838 cur += dasm.InstructionDecode(buffer, cur); 839 printf(" 0x%08x %s\n", reinterpret_cast<uint32_t>(prev), 840 buffer.start()); 841 } 842 #endif 843 } else if (strcmp(cmd, "gdb") == 0) { 844 printf("relinquishing control to gdb\n"); 845 #ifdef _MSC_VER 846 __debugbreak(); 847 #else 848 asm("int $3"); 849 #endif 850 printf("regaining control from gdb\n"); 851 } else if (strcmp(cmd, "break") == 0) { 852 if (argc == 2) { 853 int32_t value; 854 if (getValue(arg1, &value)) { 855 if (!setBreakpoint(reinterpret_cast<SimInstruction*>(value))) { 856 printf("setting breakpoint failed\n"); 857 } 858 } else { 859 printf("%s unrecognized\n", arg1); 860 } 861 } else { 862 printf("break <address>\n"); 863 } 864 } else if (strcmp(cmd, "del") == 0) { 865 if (!deleteBreakpoint(nullptr)) { 866 printf("deleting breakpoint failed\n"); 867 } 868 } else if (strcmp(cmd, "flags") == 0) { 869 printf("N flag: %d; ", sim_->n_flag_); 870 printf("Z flag: %d; ", sim_->z_flag_); 871 printf("C flag: %d; ", sim_->c_flag_); 872 printf("V flag: %d\n", sim_->v_flag_); 873 printf("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_); 874 printf("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_); 875 printf("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_); 876 printf("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_); 877 printf("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_); 878 } else if (strcmp(cmd, "stop") == 0) { 879 int32_t value; 880 intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize; 881 SimInstruction* stop_instr = reinterpret_cast<SimInstruction*>(stop_pc); 882 SimInstruction* msg_address = reinterpret_cast<SimInstruction*>( 883 stop_pc + SimInstruction::kInstrSize); 884 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) { 885 // Remove the current stop. 886 if (sim_->isStopInstruction(stop_instr)) { 887 stop_instr->setInstructionBits(kNopInstr); 888 msg_address->setInstructionBits(kNopInstr); 889 } else { 890 printf("Not at debugger stop.\n"); 891 } 892 } else if (argc == 3) { 893 // Print information about all/the specified breakpoint(s). 894 if (strcmp(arg1, "info") == 0) { 895 if (strcmp(arg2, "all") == 0) { 896 printf("Stop information:\n"); 897 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { 898 sim_->printStopInfo(i); 899 } 900 } else if (getValue(arg2, &value)) { 901 sim_->printStopInfo(value); 902 } else { 903 printf("Unrecognized argument.\n"); 904 } 905 } else if (strcmp(arg1, "enable") == 0) { 906 // Enable all/the specified breakpoint(s). 907 if (strcmp(arg2, "all") == 0) { 908 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { 909 sim_->enableStop(i); 910 } 911 } else if (getValue(arg2, &value)) { 912 sim_->enableStop(value); 913 } else { 914 printf("Unrecognized argument.\n"); 915 } 916 } else if (strcmp(arg1, "disable") == 0) { 917 // Disable all/the specified breakpoint(s). 918 if (strcmp(arg2, "all") == 0) { 919 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { 920 sim_->disableStop(i); 921 } 922 } else if (getValue(arg2, &value)) { 923 sim_->disableStop(value); 924 } else { 925 printf("Unrecognized argument.\n"); 926 } 927 } 928 } else { 929 printf("Wrong usage. Use help command for more information.\n"); 930 } 931 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) { 932 printf("cont\n"); 933 printf(" continue execution (alias 'c')\n"); 934 printf("skip\n"); 935 printf(" skip one instruction (set pc to next instruction)\n"); 936 printf("stepi\n"); 937 printf(" step one instruction (alias 'si')\n"); 938 printf("print <register>\n"); 939 printf(" print register content (alias 'p')\n"); 940 printf(" use register name 'all' to print all registers\n"); 941 printf(" add argument 'fp' to print register pair double values\n"); 942 printf("flags\n"); 943 printf(" print flags\n"); 944 printf("stack [<words>]\n"); 945 printf(" dump stack content, default dump 10 words)\n"); 946 printf("mem <address> [<words>]\n"); 947 printf(" dump memory content, default dump 10 words)\n"); 948 printf("disasm [<instructions>]\n"); 949 printf("disasm [<address/register>]\n"); 950 printf("disasm [[<address/register>] <instructions>]\n"); 951 printf(" disassemble code, default is 10 instructions\n"); 952 printf(" from pc (alias 'di')\n"); 953 printf("gdb\n"); 954 printf(" enter gdb\n"); 955 printf("break <address>\n"); 956 printf(" set a break point on the address\n"); 957 printf("del\n"); 958 printf(" delete the breakpoint\n"); 959 printf("stop feature:\n"); 960 printf(" Description:\n"); 961 printf(" Stops are debug instructions inserted by\n"); 962 printf(" the Assembler::stop() function.\n"); 963 printf(" When hitting a stop, the Simulator will\n"); 964 printf(" stop and and give control to the ArmDebugger.\n"); 965 printf(" The first %d stop codes are watched:\n", 966 Simulator::kNumOfWatchedStops); 967 printf(" - They can be enabled / disabled: the Simulator\n"); 968 printf(" will / won't stop when hitting them.\n"); 969 printf(" - The Simulator keeps track of how many times they \n"); 970 printf(" are met. (See the info command.) Going over a\n"); 971 printf(" disabled stop still increases its counter. \n"); 972 printf(" Commands:\n"); 973 printf(" stop info all/<code> : print infos about number <code>\n"); 974 printf(" or all stop(s).\n"); 975 printf(" stop enable/disable all/<code> : enables / disables\n"); 976 printf(" all or number <code> stop(s)\n"); 977 printf(" stop unstop\n"); 978 printf(" ignore the stop instruction at the current location\n"); 979 printf(" from now on\n"); 980 } else { 981 printf("Unknown command: %s\n", cmd); 982 } 983 } 984 } 985 986 // Add all the breakpoints back to stop execution and enter the debugger 987 // shell when hit. 988 redoBreakpoints(); 989 990 #undef COMMAND_SIZE 991 #undef ARG_SIZE 992 993 #undef STR 994 #undef XSTR 995 } 996 997 static bool AllOnOnePage(uintptr_t start, int size) { 998 intptr_t start_page = (start & ~CachePage::kPageMask); 999 intptr_t end_page = ((start + size) & ~CachePage::kPageMask); 1000 return start_page == end_page; 1001 } 1002 1003 static CachePage* GetCachePageLocked(SimulatorProcess::ICacheMap& i_cache, 1004 void* page) { 1005 SimulatorProcess::ICacheMap::AddPtr p = i_cache.lookupForAdd(page); 1006 if (p) { 1007 return p->value(); 1008 } 1009 1010 AutoEnterOOMUnsafeRegion oomUnsafe; 1011 CachePage* new_page = js_new<CachePage>(); 1012 if (!new_page || !i_cache.add(p, page, new_page)) { 1013 oomUnsafe.crash("Simulator CachePage"); 1014 } 1015 1016 return new_page; 1017 } 1018 1019 // Flush from start up to and not including start + size. 1020 static void FlushOnePageLocked(SimulatorProcess::ICacheMap& i_cache, 1021 intptr_t start, int size) { 1022 MOZ_ASSERT(size <= CachePage::kPageSize); 1023 MOZ_ASSERT(AllOnOnePage(start, size - 1)); 1024 MOZ_ASSERT((start & CachePage::kLineMask) == 0); 1025 MOZ_ASSERT((size & CachePage::kLineMask) == 0); 1026 1027 void* page = reinterpret_cast<void*>(start & (~CachePage::kPageMask)); 1028 int offset = (start & CachePage::kPageMask); 1029 CachePage* cache_page = GetCachePageLocked(i_cache, page); 1030 char* valid_bytemap = cache_page->validityByte(offset); 1031 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift); 1032 } 1033 1034 static void FlushICacheLocked(SimulatorProcess::ICacheMap& i_cache, 1035 void* start_addr, size_t size) { 1036 intptr_t start = reinterpret_cast<intptr_t>(start_addr); 1037 int intra_line = (start & CachePage::kLineMask); 1038 start -= intra_line; 1039 size += intra_line; 1040 size = ((size - 1) | CachePage::kLineMask) + 1; 1041 int offset = (start & CachePage::kPageMask); 1042 while (!AllOnOnePage(start, size - 1)) { 1043 int bytes_to_flush = CachePage::kPageSize - offset; 1044 FlushOnePageLocked(i_cache, start, bytes_to_flush); 1045 start += bytes_to_flush; 1046 size -= bytes_to_flush; 1047 MOZ_ASSERT((start & CachePage::kPageMask) == 0); 1048 offset = 0; 1049 } 1050 if (size != 0) { 1051 FlushOnePageLocked(i_cache, start, size); 1052 } 1053 } 1054 1055 /* static */ 1056 void SimulatorProcess::checkICacheLocked(SimInstruction* instr) { 1057 intptr_t address = reinterpret_cast<intptr_t>(instr); 1058 void* page = reinterpret_cast<void*>(address & (~CachePage::kPageMask)); 1059 void* line = reinterpret_cast<void*>(address & (~CachePage::kLineMask)); 1060 int offset = (address & CachePage::kPageMask); 1061 CachePage* cache_page = GetCachePageLocked(icache(), page); 1062 char* cache_valid_byte = cache_page->validityByte(offset); 1063 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID); 1064 char* cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask); 1065 1066 if (cache_hit) { 1067 // Check that the data in memory matches the contents of the I-cache. 1068 mozilla::DebugOnly<int> cmpret = 1069 memcmp(reinterpret_cast<void*>(instr), cache_page->cachedData(offset), 1070 SimInstruction::kInstrSize); 1071 MOZ_ASSERT(cmpret == 0); 1072 } else { 1073 // Cache miss. Load memory into the cache. 1074 memcpy(cached_line, line, CachePage::kLineLength); 1075 *cache_valid_byte = CachePage::LINE_VALID; 1076 } 1077 } 1078 1079 HashNumber SimulatorProcess::ICacheHasher::hash(const Lookup& l) { 1080 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2; 1081 } 1082 1083 bool SimulatorProcess::ICacheHasher::match(const Key& k, const Lookup& l) { 1084 MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0); 1085 MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0); 1086 return k == l; 1087 } 1088 1089 void Simulator::setLastDebuggerInput(char* input) { 1090 js_free(lastDebuggerInput_); 1091 lastDebuggerInput_ = input; 1092 } 1093 1094 /* static */ 1095 void SimulatorProcess::FlushICache(void* start_addr, size_t size) { 1096 JitSpewCont(JitSpew_CacheFlush, "[%p %zx]", start_addr, size); 1097 if (!ICacheCheckingDisableCount) { 1098 AutoLockSimulatorCache als; 1099 js::jit::FlushICacheLocked(icache(), start_addr, size); 1100 } 1101 } 1102 1103 Simulator::Simulator() { 1104 // Set up simulator support first. Some of this information is needed to 1105 // setup the architecture state. 1106 1107 // Note, allocation and anything that depends on allocated memory is 1108 // deferred until init(), in order to handle OOM properly. 1109 1110 stack_ = nullptr; 1111 stackLimit_ = 0; 1112 pc_modified_ = false; 1113 icount_ = 0L; 1114 break_pc_ = nullptr; 1115 break_instr_ = 0; 1116 single_stepping_ = false; 1117 single_step_callback_ = nullptr; 1118 single_step_callback_arg_ = nullptr; 1119 skipCalleeSavedRegsCheck = false; 1120 1121 // Set up architecture state. 1122 // All registers are initialized to zero to start with. 1123 for (int i = 0; i < num_registers; i++) { 1124 registers_[i] = 0; 1125 } 1126 1127 n_flag_ = false; 1128 z_flag_ = false; 1129 c_flag_ = false; 1130 v_flag_ = false; 1131 1132 for (int i = 0; i < num_d_registers * 2; i++) { 1133 vfp_registers_[i] = 0; 1134 } 1135 1136 n_flag_FPSCR_ = false; 1137 z_flag_FPSCR_ = false; 1138 c_flag_FPSCR_ = false; 1139 v_flag_FPSCR_ = false; 1140 FPSCR_rounding_mode_ = SimRZ; 1141 FPSCR_default_NaN_mode_ = true; 1142 1143 inv_op_vfp_flag_ = false; 1144 div_zero_vfp_flag_ = false; 1145 overflow_vfp_flag_ = false; 1146 underflow_vfp_flag_ = false; 1147 inexact_vfp_flag_ = false; 1148 1149 // The lr and pc are initialized to a known bad value that will cause an 1150 // access violation if the simulator ever tries to execute it. 1151 registers_[pc] = bad_lr; 1152 registers_[lr] = bad_lr; 1153 1154 lastDebuggerInput_ = nullptr; 1155 1156 exclusiveMonitorHeld_ = false; 1157 exclusiveMonitor_ = 0; 1158 } 1159 1160 bool Simulator::init() { 1161 // Allocate 2MB for the stack. Note that we will only use 1MB, see below. 1162 static const size_t stackSize = 2 * 1024 * 1024; 1163 stack_ = js_pod_malloc<char>(stackSize); 1164 if (!stack_) { 1165 return false; 1166 } 1167 1168 // Leave a safety margin of 1MB to prevent overrunning the stack when 1169 // pushing values (total stack size is 2MB). 1170 stackLimit_ = reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024; 1171 1172 // The sp is initialized to point to the bottom (high address) of the 1173 // allocated stack area. To be safe in potential stack underflows we leave 1174 // some buffer below. 1175 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64; 1176 1177 return true; 1178 } 1179 1180 // When the generated code calls a VM function (masm.callWithABI) we need to 1181 // call that function instead of trying to execute it with the simulator 1182 // (because it's x86 code instead of arm code). We do that by redirecting the VM 1183 // call to a svc (Supervisor Call) instruction that is handled by the 1184 // simulator. We write the original destination of the jump just at a known 1185 // offset from the svc instruction so the simulator knows what to call. 1186 class Redirection { 1187 friend class SimulatorProcess; 1188 1189 // sim's lock must already be held. 1190 Redirection(void* nativeFunction, ABIFunctionType type) 1191 : nativeFunction_(nativeFunction), 1192 swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected), 1193 type_(type), 1194 next_(nullptr) { 1195 next_ = SimulatorProcess::redirection(); 1196 if (!SimulatorProcess::ICacheCheckingDisableCount) { 1197 FlushICacheLocked(SimulatorProcess::icache(), addressOfSwiInstruction(), 1198 SimInstruction::kInstrSize); 1199 } 1200 SimulatorProcess::setRedirection(this); 1201 } 1202 1203 public: 1204 void* addressOfSwiInstruction() { return &swiInstruction_; } 1205 void* nativeFunction() const { return nativeFunction_; } 1206 ABIFunctionType type() const { return type_; } 1207 1208 static Redirection* Get(void* nativeFunction, ABIFunctionType type) { 1209 AutoLockSimulatorCache als; 1210 1211 Redirection* current = SimulatorProcess::redirection(); 1212 for (; current != nullptr; current = current->next_) { 1213 if (current->nativeFunction_ == nativeFunction) { 1214 MOZ_ASSERT(current->type() == type); 1215 return current; 1216 } 1217 } 1218 1219 // Note: we can't use js_new here because the constructor is private. 1220 AutoEnterOOMUnsafeRegion oomUnsafe; 1221 Redirection* redir = js_pod_malloc<Redirection>(1); 1222 if (!redir) { 1223 oomUnsafe.crash("Simulator redirection"); 1224 } 1225 new (redir) Redirection(nativeFunction, type); 1226 return redir; 1227 } 1228 1229 static Redirection* FromSwiInstruction(SimInstruction* swiInstruction) { 1230 uint8_t* addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction); 1231 uint8_t* addrOfRedirection = 1232 addrOfSwi - offsetof(Redirection, swiInstruction_); 1233 return reinterpret_cast<Redirection*>(addrOfRedirection); 1234 } 1235 1236 private: 1237 void* nativeFunction_; 1238 uint32_t swiInstruction_; 1239 ABIFunctionType type_; 1240 Redirection* next_; 1241 }; 1242 1243 Simulator::~Simulator() { js_free(stack_); } 1244 1245 SimulatorProcess::SimulatorProcess() 1246 : cacheLock_(mutexid::SimulatorCacheLock), redirection_(nullptr) { 1247 if (getenv("ARM_SIM_ICACHE_CHECKS")) { 1248 ICacheCheckingDisableCount = 0; 1249 } 1250 } 1251 1252 SimulatorProcess::~SimulatorProcess() { 1253 Redirection* r = redirection_; 1254 while (r) { 1255 Redirection* next = r->next_; 1256 js_delete(r); 1257 r = next; 1258 } 1259 } 1260 1261 /* static */ 1262 void* Simulator::RedirectNativeFunction(void* nativeFunction, 1263 ABIFunctionType type) { 1264 Redirection* redirection = Redirection::Get(nativeFunction, type); 1265 return redirection->addressOfSwiInstruction(); 1266 } 1267 1268 // Sets the register in the architecture state. It will also deal with updating 1269 // Simulator internal state for special registers such as PC. 1270 void Simulator::set_register(int reg, int32_t value) { 1271 MOZ_ASSERT(reg >= 0 && reg < num_registers); 1272 if (reg == pc) { 1273 pc_modified_ = true; 1274 } 1275 registers_[reg] = value; 1276 } 1277 1278 // Get the register from the architecture state. This function does handle the 1279 // special case of accessing the PC register. 1280 int32_t Simulator::get_register(int reg) const { 1281 MOZ_ASSERT(reg >= 0 && reg < num_registers); 1282 // Work around GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949 1283 if (reg >= num_registers) return 0; 1284 return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0); 1285 } 1286 1287 double Simulator::get_double_from_register_pair(int reg) { 1288 MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0); 1289 1290 // Read the bits from the unsigned integer register_[] array into the double 1291 // precision floating point value and return it. 1292 double dm_val = 0.0; 1293 char buffer[2 * sizeof(vfp_registers_[0])]; 1294 memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0])); 1295 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0])); 1296 return dm_val; 1297 } 1298 1299 void Simulator::set_register_pair_from_double(int reg, double* value) { 1300 MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0); 1301 memcpy(registers_ + reg, value, sizeof(*value)); 1302 } 1303 1304 void Simulator::set_dw_register(int dreg, const int* dbl) { 1305 MOZ_ASSERT(dreg >= 0 && dreg < num_d_registers); 1306 registers_[dreg] = dbl[0]; 1307 registers_[dreg + 1] = dbl[1]; 1308 } 1309 1310 void Simulator::get_d_register(int dreg, uint64_t* value) { 1311 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys)); 1312 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value)); 1313 } 1314 1315 void Simulator::set_d_register(int dreg, const uint64_t* value) { 1316 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys)); 1317 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value)); 1318 } 1319 1320 void Simulator::get_d_register(int dreg, uint32_t* value) { 1321 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys)); 1322 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2); 1323 } 1324 1325 void Simulator::set_d_register(int dreg, const uint32_t* value) { 1326 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::TotalPhys)); 1327 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2); 1328 } 1329 1330 void Simulator::get_q_register(int qreg, uint64_t* value) { 1331 MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers); 1332 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2); 1333 } 1334 1335 void Simulator::set_q_register(int qreg, const uint64_t* value) { 1336 MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers); 1337 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2); 1338 } 1339 1340 void Simulator::get_q_register(int qreg, uint32_t* value) { 1341 MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers); 1342 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4); 1343 } 1344 1345 void Simulator::set_q_register(int qreg, const uint32_t* value) { 1346 MOZ_ASSERT((qreg >= 0) && (qreg < num_q_registers)); 1347 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4); 1348 } 1349 1350 void Simulator::set_pc(int32_t value) { 1351 pc_modified_ = true; 1352 registers_[pc] = value; 1353 } 1354 1355 bool Simulator::has_bad_pc() const { 1356 return registers_[pc] == bad_lr || registers_[pc] == end_sim_pc; 1357 } 1358 1359 // Raw access to the PC register without the special adjustment when reading. 1360 int32_t Simulator::get_pc() const { return registers_[pc]; } 1361 1362 void Simulator::set_s_register(int sreg, unsigned int value) { 1363 MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers); 1364 vfp_registers_[sreg] = value; 1365 } 1366 1367 unsigned Simulator::get_s_register(int sreg) const { 1368 MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers); 1369 return vfp_registers_[sreg]; 1370 } 1371 1372 template <class InputType, int register_size> 1373 void Simulator::setVFPRegister(int reg_index, const InputType& value) { 1374 MOZ_ASSERT(reg_index >= 0); 1375 MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers); 1376 MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::TotalPhys)); 1377 1378 char buffer[register_size * sizeof(vfp_registers_[0])]; 1379 memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0])); 1380 memcpy(&vfp_registers_[reg_index * register_size], buffer, 1381 register_size * sizeof(vfp_registers_[0])); 1382 } 1383 1384 template <class ReturnType, int register_size> 1385 void Simulator::getFromVFPRegister(int reg_index, ReturnType* out) { 1386 MOZ_ASSERT(reg_index >= 0); 1387 MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers); 1388 MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::TotalPhys)); 1389 1390 char buffer[register_size * sizeof(vfp_registers_[0])]; 1391 memcpy(buffer, &vfp_registers_[register_size * reg_index], 1392 register_size * sizeof(vfp_registers_[0])); 1393 memcpy(out, buffer, register_size * sizeof(vfp_registers_[0])); 1394 } 1395 1396 // These forced-instantiations are for jsapi-tests. Evidently, nothing 1397 // requires these to be instantiated. 1398 template void Simulator::getFromVFPRegister<double, 2>(int reg_index, 1399 double* out); 1400 template void Simulator::getFromVFPRegister<float, 1>(int reg_index, 1401 float* out); 1402 template void Simulator::setVFPRegister<double, 2>(int reg_index, 1403 const double& value); 1404 template void Simulator::setVFPRegister<float, 1>(int reg_index, 1405 const float& value); 1406 1407 void Simulator::getFpArgs(double* x, double* y, int32_t* z) { 1408 if (ARMFlags::UseHardFpABI()) { 1409 get_double_from_d_register(0, x); 1410 get_double_from_d_register(1, y); 1411 *z = get_register(0); 1412 } else { 1413 *x = get_double_from_register_pair(0); 1414 *y = get_double_from_register_pair(2); 1415 *z = get_register(2); 1416 } 1417 } 1418 1419 void Simulator::getFpFromStack(int32_t* stack, double* x) { 1420 MOZ_ASSERT(stack && x); 1421 char buffer[2 * sizeof(stack[0])]; 1422 memcpy(buffer, stack, 2 * sizeof(stack[0])); 1423 memcpy(x, buffer, 2 * sizeof(stack[0])); 1424 } 1425 1426 void Simulator::setCallResultDouble(double result) { 1427 // The return value is either in r0/r1 or d0. 1428 if (ARMFlags::UseHardFpABI()) { 1429 char buffer[2 * sizeof(vfp_registers_[0])]; 1430 memcpy(buffer, &result, sizeof(buffer)); 1431 // Copy result to d0. 1432 memcpy(vfp_registers_, buffer, sizeof(buffer)); 1433 } else { 1434 char buffer[2 * sizeof(registers_[0])]; 1435 memcpy(buffer, &result, sizeof(buffer)); 1436 // Copy result to r0 and r1. 1437 memcpy(registers_, buffer, sizeof(buffer)); 1438 } 1439 } 1440 1441 void Simulator::setCallResultFloat(float result) { 1442 if (ARMFlags::UseHardFpABI()) { 1443 char buffer[sizeof(registers_[0])]; 1444 memcpy(buffer, &result, sizeof(buffer)); 1445 // Copy result to s0. 1446 memcpy(vfp_registers_, buffer, sizeof(buffer)); 1447 } else { 1448 char buffer[sizeof(registers_[0])]; 1449 memcpy(buffer, &result, sizeof(buffer)); 1450 // Copy result to r0. 1451 memcpy(registers_, buffer, sizeof(buffer)); 1452 } 1453 } 1454 1455 void Simulator::setCallResult(int64_t res) { 1456 set_register(r0, static_cast<int32_t>(res)); 1457 set_register(r1, static_cast<int32_t>(res >> 32)); 1458 } 1459 1460 void Simulator::exclusiveMonitorSet(uint64_t value) { 1461 exclusiveMonitor_ = value; 1462 exclusiveMonitorHeld_ = true; 1463 } 1464 1465 uint64_t Simulator::exclusiveMonitorGetAndClear(bool* held) { 1466 *held = exclusiveMonitorHeld_; 1467 exclusiveMonitorHeld_ = false; 1468 return *held ? exclusiveMonitor_ : 0; 1469 } 1470 1471 void Simulator::exclusiveMonitorClear() { exclusiveMonitorHeld_ = false; } 1472 1473 JS::ProfilingFrameIterator::RegisterState Simulator::registerState() { 1474 wasm::RegisterState state; 1475 state.pc = (void*)get_pc(); 1476 state.fp = (void*)get_register(fp); 1477 state.sp = (void*)get_register(sp); 1478 state.lr = (void*)get_register(lr); 1479 return state; 1480 } 1481 1482 uint64_t Simulator::readQ(int32_t addr, SimInstruction* instr, 1483 UnalignedPolicy f) { 1484 if (handleWasmSegFault(addr, 8)) { 1485 return UINT64_MAX; 1486 } 1487 1488 if ((addr & 3) == 0 || 1489 (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) { 1490 uint64_t* ptr = reinterpret_cast<uint64_t*>(addr); 1491 return *ptr; 1492 } 1493 1494 // See the comments below in readW. 1495 if (ARMFlags::FixupFault() && 1496 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1497 char* ptr = reinterpret_cast<char*>(addr); 1498 uint64_t value; 1499 memcpy(&value, ptr, sizeof(value)); 1500 return value; 1501 } 1502 1503 printf("Unaligned read at 0x%08x, pc=%p\n", addr, instr); 1504 MOZ_CRASH(); 1505 } 1506 1507 void Simulator::writeQ(int32_t addr, uint64_t value, SimInstruction* instr, 1508 UnalignedPolicy f) { 1509 if (handleWasmSegFault(addr, 8)) { 1510 return; 1511 } 1512 1513 if ((addr & 3) == 0 || 1514 (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) { 1515 uint64_t* ptr = reinterpret_cast<uint64_t*>(addr); 1516 *ptr = value; 1517 return; 1518 } 1519 1520 // See the comments below in readW. 1521 if (ARMFlags::FixupFault() && 1522 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1523 char* ptr = reinterpret_cast<char*>(addr); 1524 memcpy(ptr, &value, sizeof(value)); 1525 return; 1526 } 1527 1528 printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr); 1529 MOZ_CRASH(); 1530 } 1531 1532 int Simulator::readW(int32_t addr, SimInstruction* instr, UnalignedPolicy f) { 1533 if (handleWasmSegFault(addr, 4)) { 1534 return -1; 1535 } 1536 1537 if ((addr & 3) == 0 || 1538 (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) { 1539 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1540 return *ptr; 1541 } 1542 1543 // In WebAssembly, we want unaligned accesses to either raise a signal or 1544 // do the right thing. Making this simulator properly emulate the behavior 1545 // of raising a signal is complex, so as a special-case, when in wasm code, 1546 // we just do the right thing. 1547 if (ARMFlags::FixupFault() && 1548 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1549 char* ptr = reinterpret_cast<char*>(addr); 1550 int value; 1551 memcpy(&value, ptr, sizeof(value)); 1552 return value; 1553 } 1554 1555 printf("Unaligned read at 0x%08x, pc=%p\n", addr, instr); 1556 MOZ_CRASH(); 1557 } 1558 1559 void Simulator::writeW(int32_t addr, int value, SimInstruction* instr, 1560 UnalignedPolicy f) { 1561 if (handleWasmSegFault(addr, 4)) { 1562 return; 1563 } 1564 1565 if ((addr & 3) == 0 || 1566 (f == AllowUnaligned && !ARMFlags::HasAlignmentFault())) { 1567 intptr_t* ptr = reinterpret_cast<intptr_t*>(addr); 1568 *ptr = value; 1569 return; 1570 } 1571 1572 // See the comments above in readW. 1573 if (ARMFlags::FixupFault() && 1574 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1575 char* ptr = reinterpret_cast<char*>(addr); 1576 memcpy(ptr, &value, sizeof(value)); 1577 return; 1578 } 1579 1580 printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr); 1581 MOZ_CRASH(); 1582 } 1583 1584 // For the time being, define Relaxed operations in terms of SeqCst 1585 // operations - we don't yet need Relaxed operations anywhere else in 1586 // the system, and the distinction is not important to the simulation 1587 // at the level where we're operating. 1588 1589 template <typename T> 1590 static T loadRelaxed(SharedMem<T*> addr) { 1591 return AtomicOperations::loadSeqCst(addr); 1592 } 1593 1594 template <typename T> 1595 static T compareExchangeRelaxed(SharedMem<T*> addr, T oldval, T newval) { 1596 return AtomicOperations::compareExchangeSeqCst(addr, oldval, newval); 1597 } 1598 1599 int Simulator::readExW(int32_t addr, SimInstruction* instr) { 1600 if (addr & 3) { 1601 MOZ_CRASH("Unaligned exclusive read"); 1602 } 1603 1604 if (handleWasmSegFault(addr, 4)) { 1605 return -1; 1606 } 1607 1608 SharedMem<int32_t*> ptr = 1609 SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr)); 1610 int32_t value = loadRelaxed(ptr); 1611 exclusiveMonitorSet(value); 1612 return value; 1613 } 1614 1615 int32_t Simulator::writeExW(int32_t addr, int value, SimInstruction* instr) { 1616 if (addr & 3) { 1617 MOZ_CRASH("Unaligned exclusive write"); 1618 } 1619 1620 if (handleWasmSegFault(addr, 4)) { 1621 return -1; 1622 } 1623 1624 SharedMem<int32_t*> ptr = 1625 SharedMem<int32_t*>::shared(reinterpret_cast<int32_t*>(addr)); 1626 bool held; 1627 int32_t expected = int32_t(exclusiveMonitorGetAndClear(&held)); 1628 if (!held) { 1629 return 1; 1630 } 1631 int32_t old = compareExchangeRelaxed(ptr, expected, int32_t(value)); 1632 return old != expected; 1633 } 1634 1635 uint16_t Simulator::readHU(int32_t addr, SimInstruction* instr) { 1636 if (handleWasmSegFault(addr, 2)) { 1637 return UINT16_MAX; 1638 } 1639 1640 // The regexp engine emits unaligned loads, so we don't check for them here 1641 // like most of the other methods do. 1642 if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) { 1643 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1644 return *ptr; 1645 } 1646 1647 // See comments above in readW. 1648 if (ARMFlags::FixupFault() && 1649 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1650 char* ptr = reinterpret_cast<char*>(addr); 1651 uint16_t value; 1652 memcpy(&value, ptr, sizeof(value)); 1653 return value; 1654 } 1655 1656 printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr); 1657 MOZ_CRASH(); 1658 return 0; 1659 } 1660 1661 int16_t Simulator::readH(int32_t addr, SimInstruction* instr) { 1662 if (handleWasmSegFault(addr, 2)) { 1663 return -1; 1664 } 1665 1666 if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) { 1667 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1668 return *ptr; 1669 } 1670 1671 // See comments above in readW. 1672 if (ARMFlags::FixupFault() && 1673 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1674 char* ptr = reinterpret_cast<char*>(addr); 1675 int16_t value; 1676 memcpy(&value, ptr, sizeof(value)); 1677 return value; 1678 } 1679 1680 printf("Unaligned signed halfword read at 0x%08x\n", addr); 1681 MOZ_CRASH(); 1682 return 0; 1683 } 1684 1685 void Simulator::writeH(int32_t addr, uint16_t value, SimInstruction* instr) { 1686 if (handleWasmSegFault(addr, 2)) { 1687 return; 1688 } 1689 1690 if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) { 1691 uint16_t* ptr = reinterpret_cast<uint16_t*>(addr); 1692 *ptr = value; 1693 return; 1694 } 1695 1696 // See the comments above in readW. 1697 if (ARMFlags::FixupFault() && 1698 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1699 char* ptr = reinterpret_cast<char*>(addr); 1700 memcpy(ptr, &value, sizeof(value)); 1701 return; 1702 } 1703 1704 printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr); 1705 MOZ_CRASH(); 1706 } 1707 1708 void Simulator::writeH(int32_t addr, int16_t value, SimInstruction* instr) { 1709 if (handleWasmSegFault(addr, 2)) { 1710 return; 1711 } 1712 1713 if ((addr & 1) == 0 || !ARMFlags::HasAlignmentFault()) { 1714 int16_t* ptr = reinterpret_cast<int16_t*>(addr); 1715 *ptr = value; 1716 return; 1717 } 1718 1719 // See the comments above in readW. 1720 if (ARMFlags::FixupFault() && 1721 wasm::InCompiledCode(reinterpret_cast<void*>(get_pc()))) { 1722 char* ptr = reinterpret_cast<char*>(addr); 1723 memcpy(ptr, &value, sizeof(value)); 1724 return; 1725 } 1726 1727 printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr); 1728 MOZ_CRASH(); 1729 } 1730 1731 uint16_t Simulator::readExHU(int32_t addr, SimInstruction* instr) { 1732 if (addr & 1) { 1733 MOZ_CRASH("Unaligned exclusive read"); 1734 } 1735 1736 if (handleWasmSegFault(addr, 2)) { 1737 return UINT16_MAX; 1738 } 1739 1740 SharedMem<uint16_t*> ptr = 1741 SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr)); 1742 uint16_t value = loadRelaxed(ptr); 1743 exclusiveMonitorSet(value); 1744 return value; 1745 } 1746 1747 int32_t Simulator::writeExH(int32_t addr, uint16_t value, 1748 SimInstruction* instr) { 1749 if (addr & 1) { 1750 MOZ_CRASH("Unaligned exclusive write"); 1751 } 1752 1753 if (handleWasmSegFault(addr, 2)) { 1754 return -1; 1755 } 1756 1757 SharedMem<uint16_t*> ptr = 1758 SharedMem<uint16_t*>::shared(reinterpret_cast<uint16_t*>(addr)); 1759 bool held; 1760 uint16_t expected = uint16_t(exclusiveMonitorGetAndClear(&held)); 1761 if (!held) { 1762 return 1; 1763 } 1764 uint16_t old = compareExchangeRelaxed(ptr, expected, value); 1765 return old != expected; 1766 } 1767 1768 uint8_t Simulator::readBU(int32_t addr) { 1769 if (handleWasmSegFault(addr, 1)) { 1770 return UINT8_MAX; 1771 } 1772 1773 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1774 return *ptr; 1775 } 1776 1777 uint8_t Simulator::readExBU(int32_t addr) { 1778 if (handleWasmSegFault(addr, 1)) { 1779 return UINT8_MAX; 1780 } 1781 1782 SharedMem<uint8_t*> ptr = 1783 SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr)); 1784 uint8_t value = loadRelaxed(ptr); 1785 exclusiveMonitorSet(value); 1786 return value; 1787 } 1788 1789 int32_t Simulator::writeExB(int32_t addr, uint8_t value) { 1790 if (handleWasmSegFault(addr, 1)) { 1791 return -1; 1792 } 1793 1794 SharedMem<uint8_t*> ptr = 1795 SharedMem<uint8_t*>::shared(reinterpret_cast<uint8_t*>(addr)); 1796 bool held; 1797 uint8_t expected = uint8_t(exclusiveMonitorGetAndClear(&held)); 1798 if (!held) { 1799 return 1; 1800 } 1801 uint8_t old = compareExchangeRelaxed(ptr, expected, value); 1802 return old != expected; 1803 } 1804 1805 int8_t Simulator::readB(int32_t addr) { 1806 if (handleWasmSegFault(addr, 1)) { 1807 return -1; 1808 } 1809 1810 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1811 return *ptr; 1812 } 1813 1814 void Simulator::writeB(int32_t addr, uint8_t value) { 1815 if (handleWasmSegFault(addr, 1)) { 1816 return; 1817 } 1818 1819 uint8_t* ptr = reinterpret_cast<uint8_t*>(addr); 1820 *ptr = value; 1821 } 1822 1823 void Simulator::writeB(int32_t addr, int8_t value) { 1824 if (handleWasmSegFault(addr, 1)) { 1825 return; 1826 } 1827 1828 int8_t* ptr = reinterpret_cast<int8_t*>(addr); 1829 *ptr = value; 1830 } 1831 1832 int32_t* Simulator::readDW(int32_t addr) { 1833 if (handleWasmSegFault(addr, 8)) { 1834 return nullptr; 1835 } 1836 1837 if ((addr & 3) == 0) { 1838 int32_t* ptr = reinterpret_cast<int32_t*>(addr); 1839 return ptr; 1840 } 1841 1842 printf("Unaligned read at 0x%08x\n", addr); 1843 MOZ_CRASH(); 1844 } 1845 1846 void Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2) { 1847 if (handleWasmSegFault(addr, 8)) { 1848 return; 1849 } 1850 1851 if ((addr & 3) == 0) { 1852 int32_t* ptr = reinterpret_cast<int32_t*>(addr); 1853 *ptr++ = value1; 1854 *ptr = value2; 1855 return; 1856 } 1857 1858 printf("Unaligned write at 0x%08x\n", addr); 1859 MOZ_CRASH(); 1860 } 1861 1862 int32_t Simulator::readExDW(int32_t addr, int32_t* hibits) { 1863 if (addr & 3) { 1864 MOZ_CRASH("Unaligned exclusive read"); 1865 } 1866 1867 if (handleWasmSegFault(addr, 8)) { 1868 return -1; 1869 } 1870 1871 SharedMem<uint64_t*> ptr = 1872 SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr)); 1873 // The spec says that the low part of value shall be read from addr and 1874 // the high part shall be read from addr+4. On a little-endian system 1875 // where we read a 64-bit quadword the low part of the value will be in 1876 // the low part of the quadword, and the high part of the value in the 1877 // high part of the quadword. 1878 uint64_t value = loadRelaxed(ptr); 1879 exclusiveMonitorSet(value); 1880 *hibits = int32_t(value >> 32); 1881 return int32_t(value); 1882 } 1883 1884 int32_t Simulator::writeExDW(int32_t addr, int32_t value1, int32_t value2) { 1885 if (addr & 3) { 1886 MOZ_CRASH("Unaligned exclusive write"); 1887 } 1888 1889 if (handleWasmSegFault(addr, 8)) { 1890 return -1; 1891 } 1892 1893 SharedMem<uint64_t*> ptr = 1894 SharedMem<uint64_t*>::shared(reinterpret_cast<uint64_t*>(addr)); 1895 // The spec says that value1 shall be stored at addr and value2 at 1896 // addr+4. On a little-endian system that means constructing a 64-bit 1897 // value where value1 is in the low half of a 64-bit quadword and value2 1898 // is in the high half of the quadword. 1899 uint64_t value = (uint64_t(value2) << 32) | uint32_t(value1); 1900 bool held; 1901 uint64_t expected = exclusiveMonitorGetAndClear(&held); 1902 if (!held) { 1903 return 1; 1904 } 1905 uint64_t old = compareExchangeRelaxed(ptr, expected, value); 1906 return old != expected; 1907 } 1908 1909 uintptr_t Simulator::stackLimit() const { return stackLimit_; } 1910 1911 uintptr_t* Simulator::addressOfStackLimit() { return &stackLimit_; } 1912 1913 bool Simulator::overRecursed(uintptr_t newsp) const { 1914 if (newsp == 0) { 1915 newsp = get_register(sp); 1916 } 1917 return newsp <= stackLimit(); 1918 } 1919 1920 bool Simulator::overRecursedWithExtra(uint32_t extra) const { 1921 uintptr_t newsp = get_register(sp) - extra; 1922 return newsp <= stackLimit(); 1923 } 1924 1925 // Checks if the current instruction should be executed based on its condition 1926 // bits. 1927 bool Simulator::conditionallyExecute(SimInstruction* instr) { 1928 switch (instr->conditionField()) { 1929 case Assembler::EQ: 1930 return z_flag_; 1931 case Assembler::NE: 1932 return !z_flag_; 1933 case Assembler::CS: 1934 return c_flag_; 1935 case Assembler::CC: 1936 return !c_flag_; 1937 case Assembler::MI: 1938 return n_flag_; 1939 case Assembler::PL: 1940 return !n_flag_; 1941 case Assembler::VS: 1942 return v_flag_; 1943 case Assembler::VC: 1944 return !v_flag_; 1945 case Assembler::HI: 1946 return c_flag_ && !z_flag_; 1947 case Assembler::LS: 1948 return !c_flag_ || z_flag_; 1949 case Assembler::GE: 1950 return n_flag_ == v_flag_; 1951 case Assembler::LT: 1952 return n_flag_ != v_flag_; 1953 case Assembler::GT: 1954 return !z_flag_ && (n_flag_ == v_flag_); 1955 case Assembler::LE: 1956 return z_flag_ || (n_flag_ != v_flag_); 1957 case Assembler::AL: 1958 return true; 1959 default: 1960 MOZ_CRASH(); 1961 } 1962 return false; 1963 } 1964 1965 // Calculate and set the Negative and Zero flags. 1966 void Simulator::setNZFlags(int32_t val) { 1967 n_flag_ = (val < 0); 1968 z_flag_ = (val == 0); 1969 } 1970 1971 // Set the Carry flag. 1972 void Simulator::setCFlag(bool val) { c_flag_ = val; } 1973 1974 // Set the oVerflow flag. 1975 void Simulator::setVFlag(bool val) { v_flag_ = val; } 1976 1977 // Calculate C flag value for additions. 1978 bool Simulator::carryFrom(int32_t left, int32_t right, int32_t carry) { 1979 uint32_t uleft = static_cast<uint32_t>(left); 1980 uint32_t uright = static_cast<uint32_t>(right); 1981 uint32_t urest = 0xffffffffU - uleft; 1982 return (uright > urest) || 1983 (carry && (((uright + 1) > urest) || (uright > (urest - 1)))); 1984 } 1985 1986 // Calculate C flag value for subtractions. 1987 bool Simulator::borrowFrom(int32_t left, int32_t right) { 1988 uint32_t uleft = static_cast<uint32_t>(left); 1989 uint32_t uright = static_cast<uint32_t>(right); 1990 return (uright > uleft); 1991 } 1992 1993 // Calculate V flag value for additions and subtractions. 1994 bool Simulator::overflowFrom(int32_t alu_out, int32_t left, int32_t right, 1995 bool addition) { 1996 bool overflow; 1997 if (addition) { 1998 // Operands have the same sign. 1999 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0)) 2000 // And operands and result have different sign. 2001 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); 2002 } else { 2003 // Operands have different signs. 2004 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0)) 2005 // And first operand and result have different signs. 2006 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0)); 2007 } 2008 return overflow; 2009 } 2010 2011 // Support for VFP comparisons. 2012 void Simulator::compute_FPSCR_Flags(double val1, double val2) { 2013 if (std::isnan(val1) || std::isnan(val2)) { 2014 n_flag_FPSCR_ = false; 2015 z_flag_FPSCR_ = false; 2016 c_flag_FPSCR_ = true; 2017 v_flag_FPSCR_ = true; 2018 // All non-NaN cases. 2019 } else if (val1 == val2) { 2020 n_flag_FPSCR_ = false; 2021 z_flag_FPSCR_ = true; 2022 c_flag_FPSCR_ = true; 2023 v_flag_FPSCR_ = false; 2024 } else if (val1 < val2) { 2025 n_flag_FPSCR_ = true; 2026 z_flag_FPSCR_ = false; 2027 c_flag_FPSCR_ = false; 2028 v_flag_FPSCR_ = false; 2029 } else { 2030 // Case when (val1 > val2). 2031 n_flag_FPSCR_ = false; 2032 z_flag_FPSCR_ = false; 2033 c_flag_FPSCR_ = true; 2034 v_flag_FPSCR_ = false; 2035 } 2036 } 2037 2038 void Simulator::copy_FPSCR_to_APSR() { 2039 n_flag_ = n_flag_FPSCR_; 2040 z_flag_ = z_flag_FPSCR_; 2041 c_flag_ = c_flag_FPSCR_; 2042 v_flag_ = v_flag_FPSCR_; 2043 } 2044 2045 // Addressing Mode 1 - Data-processing operands: 2046 // Get the value based on the shifter_operand with register. 2047 int32_t Simulator::getShiftRm(SimInstruction* instr, bool* carry_out) { 2048 ShiftType shift = instr->shifttypeValue(); 2049 int shift_amount = instr->shiftAmountValue(); 2050 int32_t result = get_register(instr->rmValue()); 2051 if (instr->bit(4) == 0) { 2052 // By immediate. 2053 if (shift == ROR && shift_amount == 0) { 2054 MOZ_CRASH("NYI"); 2055 return result; 2056 } 2057 if ((shift == LSR || shift == ASR) && shift_amount == 0) { 2058 shift_amount = 32; 2059 } 2060 switch (shift) { 2061 case ASR: { 2062 if (shift_amount == 0) { 2063 if (result < 0) { 2064 result = 0xffffffff; 2065 *carry_out = true; 2066 } else { 2067 result = 0; 2068 *carry_out = false; 2069 } 2070 } else { 2071 result >>= (shift_amount - 1); 2072 *carry_out = (result & 1) == 1; 2073 result >>= 1; 2074 } 2075 break; 2076 } 2077 2078 case LSL: { 2079 if (shift_amount == 0) { 2080 *carry_out = c_flag_; 2081 } else { 2082 result <<= (shift_amount - 1); 2083 *carry_out = (result < 0); 2084 result <<= 1; 2085 } 2086 break; 2087 } 2088 2089 case LSR: { 2090 if (shift_amount == 0) { 2091 result = 0; 2092 *carry_out = c_flag_; 2093 } else { 2094 uint32_t uresult = static_cast<uint32_t>(result); 2095 uresult >>= (shift_amount - 1); 2096 *carry_out = (uresult & 1) == 1; 2097 uresult >>= 1; 2098 result = static_cast<int32_t>(uresult); 2099 } 2100 break; 2101 } 2102 2103 case ROR: { 2104 if (shift_amount == 0) { 2105 *carry_out = c_flag_; 2106 } else { 2107 uint32_t left = static_cast<uint32_t>(result) >> shift_amount; 2108 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount); 2109 result = right | left; 2110 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0; 2111 } 2112 break; 2113 } 2114 2115 default: 2116 MOZ_CRASH(); 2117 } 2118 } else { 2119 // By register. 2120 int rs = instr->rsValue(); 2121 shift_amount = get_register(rs) & 0xff; 2122 switch (shift) { 2123 case ASR: { 2124 if (shift_amount == 0) { 2125 *carry_out = c_flag_; 2126 } else if (shift_amount < 32) { 2127 result >>= (shift_amount - 1); 2128 *carry_out = (result & 1) == 1; 2129 result >>= 1; 2130 } else { 2131 MOZ_ASSERT(shift_amount >= 32); 2132 if (result < 0) { 2133 *carry_out = true; 2134 result = 0xffffffff; 2135 } else { 2136 *carry_out = false; 2137 result = 0; 2138 } 2139 } 2140 break; 2141 } 2142 2143 case LSL: { 2144 if (shift_amount == 0) { 2145 *carry_out = c_flag_; 2146 } else if (shift_amount < 32) { 2147 result <<= (shift_amount - 1); 2148 *carry_out = (result < 0); 2149 result <<= 1; 2150 } else if (shift_amount == 32) { 2151 *carry_out = (result & 1) == 1; 2152 result = 0; 2153 } else { 2154 MOZ_ASSERT(shift_amount > 32); 2155 *carry_out = false; 2156 result = 0; 2157 } 2158 break; 2159 } 2160 2161 case LSR: { 2162 if (shift_amount == 0) { 2163 *carry_out = c_flag_; 2164 } else if (shift_amount < 32) { 2165 uint32_t uresult = static_cast<uint32_t>(result); 2166 uresult >>= (shift_amount - 1); 2167 *carry_out = (uresult & 1) == 1; 2168 uresult >>= 1; 2169 result = static_cast<int32_t>(uresult); 2170 } else if (shift_amount == 32) { 2171 *carry_out = (result < 0); 2172 result = 0; 2173 } else { 2174 *carry_out = false; 2175 result = 0; 2176 } 2177 break; 2178 } 2179 2180 case ROR: { 2181 if (shift_amount == 0) { 2182 *carry_out = c_flag_; 2183 } else { 2184 uint32_t left = static_cast<uint32_t>(result) >> shift_amount; 2185 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount); 2186 result = right | left; 2187 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0; 2188 } 2189 break; 2190 } 2191 2192 default: 2193 MOZ_CRASH(); 2194 } 2195 } 2196 return result; 2197 } 2198 2199 // Addressing Mode 1 - Data-processing operands: 2200 // Get the value based on the shifter_operand with immediate. 2201 int32_t Simulator::getImm(SimInstruction* instr, bool* carry_out) { 2202 int rotate = instr->rotateValue() * 2; 2203 int immed8 = instr->immed8Value(); 2204 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); 2205 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0); 2206 return imm; 2207 } 2208 2209 int32_t Simulator::processPU(SimInstruction* instr, int num_regs, int reg_size, 2210 intptr_t* start_address, intptr_t* end_address) { 2211 int rn = instr->rnValue(); 2212 int32_t rn_val = get_register(rn); 2213 switch (instr->PUField()) { 2214 case da_x: 2215 MOZ_CRASH(); 2216 break; 2217 case ia_x: 2218 *start_address = rn_val; 2219 *end_address = rn_val + (num_regs * reg_size) - reg_size; 2220 rn_val = rn_val + (num_regs * reg_size); 2221 break; 2222 case db_x: 2223 *start_address = rn_val - (num_regs * reg_size); 2224 *end_address = rn_val - reg_size; 2225 rn_val = *start_address; 2226 break; 2227 case ib_x: 2228 *start_address = rn_val + reg_size; 2229 *end_address = rn_val + (num_regs * reg_size); 2230 rn_val = *end_address; 2231 break; 2232 default: 2233 MOZ_CRASH(); 2234 } 2235 return rn_val; 2236 } 2237 2238 // Addressing Mode 4 - Load and Store Multiple 2239 void Simulator::handleRList(SimInstruction* instr, bool load) { 2240 int rlist = instr->rlistValue(); 2241 int num_regs = mozilla::CountPopulation32(rlist); 2242 2243 intptr_t start_address = 0; 2244 intptr_t end_address = 0; 2245 int32_t rn_val = 2246 processPU(instr, num_regs, sizeof(void*), &start_address, &end_address); 2247 intptr_t* address = reinterpret_cast<intptr_t*>(start_address); 2248 2249 // Catch null pointers a little earlier. 2250 MOZ_ASSERT(start_address > 8191 || start_address < 0); 2251 2252 int reg = 0; 2253 while (rlist != 0) { 2254 if ((rlist & 1) != 0) { 2255 if (load) { 2256 set_register(reg, *address); 2257 } else { 2258 *address = get_register(reg); 2259 } 2260 address += 1; 2261 } 2262 reg++; 2263 rlist >>= 1; 2264 } 2265 MOZ_ASSERT(end_address == ((intptr_t)address) - 4); 2266 if (instr->hasW()) { 2267 set_register(instr->rnValue(), rn_val); 2268 } 2269 } 2270 2271 // Addressing Mode 6 - Load and Store Multiple Coprocessor registers. 2272 void Simulator::handleVList(SimInstruction* instr) { 2273 VFPRegPrecision precision = 2274 (instr->szValue() == 0) ? kSinglePrecision : kDoublePrecision; 2275 int operand_size = (precision == kSinglePrecision) ? 4 : 8; 2276 bool load = (instr->VLValue() == 0x1); 2277 2278 int vd; 2279 int num_regs; 2280 vd = instr->VFPDRegValue(precision); 2281 if (precision == kSinglePrecision) { 2282 num_regs = instr->immed8Value(); 2283 } else { 2284 num_regs = instr->immed8Value() / 2; 2285 } 2286 2287 intptr_t start_address = 0; 2288 intptr_t end_address = 0; 2289 int32_t rn_val = 2290 processPU(instr, num_regs, operand_size, &start_address, &end_address); 2291 2292 intptr_t* address = reinterpret_cast<intptr_t*>(start_address); 2293 for (int reg = vd; reg < vd + num_regs; reg++) { 2294 if (precision == kSinglePrecision) { 2295 if (load) { 2296 set_s_register_from_sinteger( 2297 reg, readW(reinterpret_cast<int32_t>(address), instr)); 2298 } else { 2299 writeW(reinterpret_cast<int32_t>(address), 2300 get_sinteger_from_s_register(reg), instr); 2301 } 2302 address += 1; 2303 } else { 2304 if (load) { 2305 int32_t data[] = {readW(reinterpret_cast<int32_t>(address), instr), 2306 readW(reinterpret_cast<int32_t>(address + 1), instr)}; 2307 double d; 2308 memcpy(&d, data, 8); 2309 set_d_register_from_double(reg, d); 2310 } else { 2311 int32_t data[2]; 2312 double d; 2313 get_double_from_d_register(reg, &d); 2314 memcpy(data, &d, 8); 2315 writeW(reinterpret_cast<int32_t>(address), data[0], instr); 2316 writeW(reinterpret_cast<int32_t>(address + 1), data[1], instr); 2317 } 2318 address += 2; 2319 } 2320 } 2321 MOZ_ASSERT(reinterpret_cast<intptr_t>(address) - operand_size == end_address); 2322 if (instr->hasW()) { 2323 set_register(instr->rnValue(), rn_val); 2324 } 2325 } 2326 2327 ABI_FUNCTION_TYPE_SIM_PROTOTYPES 2328 2329 // Fill the volatile registers with scratch values. 2330 // 2331 // Some of the ABI calls assume that the float registers are not scratched, 2332 // even though the ABI defines them as volatile - a performance 2333 // optimization. These are all calls passing operands in integer registers, 2334 // so for now the simulator does not scratch any float registers for these 2335 // calls. Should try to narrow it further in future. 2336 // 2337 void Simulator::scratchVolatileRegisters(void* target) { 2338 // The ARM backend makes calls to __aeabi_idivmod and 2339 // __aeabi_uidivmod assuming that the float registers are 2340 // non-volatile as a performance optimization, so the float 2341 // registers must not be scratch when calling these. 2342 bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod; 2343 int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_); 2344 set_register(r0, scratch_value); 2345 set_register(r1, scratch_value); 2346 set_register(r2, scratch_value); 2347 set_register(r3, scratch_value); 2348 set_register(r12, scratch_value); // Intra-Procedure-call scratch register. 2349 set_register(r14, scratch_value); // Link register. 2350 2351 if (scratchFloat) { 2352 uint64_t scratch_value_d = 2353 0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30); 2354 for (uint32_t i = d0; i < d8; i++) { 2355 set_d_register(i, &scratch_value_d); 2356 } 2357 for (uint32_t i = d16; i < FloatRegisters::TotalPhys; i++) { 2358 set_d_register(i, &scratch_value_d); 2359 } 2360 } 2361 } 2362 2363 static int64_t MakeInt64(int32_t first, int32_t second) { 2364 // Little-endian order. 2365 return ((int64_t)second << 32) | (uint32_t)first; 2366 } 2367 2368 // Software interrupt instructions are used by the simulator to call into C++. 2369 void Simulator::softwareInterrupt(SimInstruction* instr) { 2370 int svc = instr->svcValue(); 2371 switch (svc) { 2372 case kCallRtRedirected: { 2373 Redirection* redirection = Redirection::FromSwiInstruction(instr); 2374 int32_t* stack_pointer = reinterpret_cast<int32_t*>(get_register(sp)); 2375 int32_t a0 = get_register(r0); 2376 int32_t a1 = get_register(r1); 2377 int32_t a2 = get_register(r2); 2378 int32_t a3 = get_register(r3); 2379 float s0, s1, s2, s3, s4; 2380 get_float_from_s_register(0, &s0); 2381 get_float_from_s_register(0, &s1); 2382 get_float_from_s_register(0, &s2); 2383 get_float_from_s_register(0, &s3); 2384 get_float_from_s_register(0, &s4); 2385 double d0, d1, d2, d3, d4; 2386 get_double_from_d_register(0, &d0); 2387 get_double_from_d_register(1, &d1); 2388 get_double_from_d_register(2, &d2); 2389 get_double_from_d_register(3, &d3); 2390 get_double_from_d_register(4, &d4); 2391 2392 int32_t saved_lr = get_register(lr); 2393 intptr_t external = 2394 reinterpret_cast<intptr_t>(redirection->nativeFunction()); 2395 2396 bool stack_aligned = (get_register(sp) & (ABIStackAlignment - 1)) == 0; 2397 if (!stack_aligned) { 2398 fprintf(stderr, "Runtime call with unaligned stack!\n"); 2399 MOZ_CRASH(); 2400 } 2401 2402 if (single_stepping_) { 2403 single_step_callback_(single_step_callback_arg_, this, nullptr); 2404 } 2405 2406 switch (redirection->type()) { 2407 ABI_FUNCTION_TYPE_ARM32_SIM_DISPATCH 2408 default: 2409 MOZ_CRASH("call"); 2410 } 2411 2412 if (single_stepping_) { 2413 single_step_callback_(single_step_callback_arg_, this, nullptr); 2414 } 2415 2416 set_register(lr, saved_lr); 2417 set_pc(get_register(lr)); 2418 break; 2419 } 2420 case kBreakpoint: { 2421 ArmDebugger dbg(this); 2422 dbg.debug(); 2423 break; 2424 } 2425 default: { // Stop uses all codes greater than 1 << 23. 2426 if (svc >= (1 << 23)) { 2427 uint32_t code = svc & kStopCodeMask; 2428 if (isWatchedStop(code)) { 2429 increaseStopCounter(code); 2430 } 2431 2432 // Stop if it is enabled, otherwise go on jumping over the stop and 2433 // the message address. 2434 if (isEnabledStop(code)) { 2435 ArmDebugger dbg(this); 2436 dbg.stop(instr); 2437 } else { 2438 set_pc(get_pc() + 2 * SimInstruction::kInstrSize); 2439 } 2440 } else { 2441 // This is not a valid svc code. 2442 MOZ_CRASH(); 2443 break; 2444 } 2445 } 2446 } 2447 } 2448 2449 void Simulator::canonicalizeNaN(double* value) { 2450 if (!wasm::CodeExists && !wasm::LookupCodeBlock(get_pc_as<void*>()) && 2451 FPSCR_default_NaN_mode_) { 2452 *value = JS::CanonicalizeNaN(*value); 2453 } 2454 } 2455 2456 void Simulator::canonicalizeNaN(float* value) { 2457 if (!wasm::CodeExists && !wasm::LookupCodeBlock(get_pc_as<void*>()) && 2458 FPSCR_default_NaN_mode_) { 2459 *value = JS::CanonicalizeNaN(*value); 2460 } 2461 } 2462 2463 // Stop helper functions. 2464 bool Simulator::isStopInstruction(SimInstruction* instr) { 2465 return (instr->bits(27, 24) == 0xF) && (instr->svcValue() >= kStopCode); 2466 } 2467 2468 bool Simulator::isWatchedStop(uint32_t code) { 2469 MOZ_ASSERT(code <= kMaxStopCode); 2470 return code < kNumOfWatchedStops; 2471 } 2472 2473 bool Simulator::isEnabledStop(uint32_t code) { 2474 MOZ_ASSERT(code <= kMaxStopCode); 2475 // Unwatched stops are always enabled. 2476 return !isWatchedStop(code) || 2477 !(watched_stops_[code].count & kStopDisabledBit); 2478 } 2479 2480 void Simulator::enableStop(uint32_t code) { 2481 MOZ_ASSERT(isWatchedStop(code)); 2482 if (!isEnabledStop(code)) { 2483 watched_stops_[code].count &= ~kStopDisabledBit; 2484 } 2485 } 2486 2487 void Simulator::disableStop(uint32_t code) { 2488 MOZ_ASSERT(isWatchedStop(code)); 2489 if (isEnabledStop(code)) { 2490 watched_stops_[code].count |= kStopDisabledBit; 2491 } 2492 } 2493 2494 void Simulator::increaseStopCounter(uint32_t code) { 2495 MOZ_ASSERT(code <= kMaxStopCode); 2496 MOZ_ASSERT(isWatchedStop(code)); 2497 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) { 2498 printf( 2499 "Stop counter for code %i has overflowed.\n" 2500 "Enabling this code and reseting the counter to 0.\n", 2501 code); 2502 watched_stops_[code].count = 0; 2503 enableStop(code); 2504 } else { 2505 watched_stops_[code].count++; 2506 } 2507 } 2508 2509 // Print a stop status. 2510 void Simulator::printStopInfo(uint32_t code) { 2511 MOZ_ASSERT(code <= kMaxStopCode); 2512 if (!isWatchedStop(code)) { 2513 printf("Stop not watched."); 2514 } else { 2515 const char* state = isEnabledStop(code) ? "Enabled" : "Disabled"; 2516 int32_t count = watched_stops_[code].count & ~kStopDisabledBit; 2517 // Don't print the state of unused breakpoints. 2518 if (count != 0) { 2519 if (watched_stops_[code].desc) { 2520 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", code, code, 2521 state, count, watched_stops_[code].desc); 2522 } else { 2523 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n", code, code, state, 2524 count); 2525 } 2526 } 2527 } 2528 } 2529 2530 // Instruction types 0 and 1 are both rolled into one function because they only 2531 // differ in the handling of the shifter_operand. 2532 void Simulator::decodeType01(SimInstruction* instr) { 2533 int type = instr->typeValue(); 2534 if (type == 0 && instr->isSpecialType0()) { 2535 // Multiply instruction or extra loads and stores. 2536 if (instr->bits(7, 4) == 9) { 2537 if (instr->bit(24) == 0) { 2538 // Raw field decoding here. Multiply instructions have their Rd 2539 // in funny places. 2540 int rn = instr->rnValue(); 2541 int rm = instr->rmValue(); 2542 int rs = instr->rsValue(); 2543 int32_t rs_val = get_register(rs); 2544 int32_t rm_val = get_register(rm); 2545 if (instr->bit(23) == 0) { 2546 if (instr->bit(21) == 0) { 2547 // The MUL instruction description (A 4.1.33) refers to 2548 // Rd as being the destination for the operation, but it 2549 // confusingly uses the Rn field to encode it. 2550 int rd = rn; // Remap the rn field to the Rd register. 2551 int32_t alu_out = rm_val * rs_val; 2552 set_register(rd, alu_out); 2553 if (instr->hasS()) { 2554 setNZFlags(alu_out); 2555 } 2556 } else { 2557 int rd = instr->rdValue(); 2558 int32_t acc_value = get_register(rd); 2559 if (instr->bit(22) == 0) { 2560 // The MLA instruction description (A 4.1.28) refers 2561 // to the order of registers as "Rd, Rm, Rs, 2562 // Rn". But confusingly it uses the Rn field to 2563 // encode the Rd register and the Rd field to encode 2564 // the Rn register. 2565 int32_t mul_out = rm_val * rs_val; 2566 int32_t result = acc_value + mul_out; 2567 set_register(rn, result); 2568 } else { 2569 int32_t mul_out = rm_val * rs_val; 2570 int32_t result = acc_value - mul_out; 2571 set_register(rn, result); 2572 } 2573 } 2574 } else { 2575 // The signed/long multiply instructions use the terms RdHi 2576 // and RdLo when referring to the target registers. They are 2577 // mapped to the Rn and Rd fields as follows: 2578 // RdLo == Rd 2579 // RdHi == Rn (This is confusingly stored in variable rd here 2580 // because the mul instruction from above uses the 2581 // Rn field to encode the Rd register. Good luck figuring 2582 // this out without reading the ARM instruction manual 2583 // at a very detailed level.) 2584 int rd_hi = rn; // Remap the rn field to the RdHi register. 2585 int rd_lo = instr->rdValue(); 2586 int32_t hi_res = 0; 2587 int32_t lo_res = 0; 2588 if (instr->bit(22) == 1) { 2589 int64_t left_op = static_cast<int32_t>(rm_val); 2590 int64_t right_op = static_cast<int32_t>(rs_val); 2591 uint64_t result = left_op * right_op; 2592 hi_res = static_cast<int32_t>(result >> 32); 2593 lo_res = static_cast<int32_t>(result & 0xffffffff); 2594 } else { 2595 // Unsigned multiply. 2596 uint64_t left_op = static_cast<uint32_t>(rm_val); 2597 uint64_t right_op = static_cast<uint32_t>(rs_val); 2598 uint64_t result = left_op * right_op; 2599 hi_res = static_cast<int32_t>(result >> 32); 2600 lo_res = static_cast<int32_t>(result & 0xffffffff); 2601 } 2602 set_register(rd_lo, lo_res); 2603 set_register(rd_hi, hi_res); 2604 if (instr->hasS()) { 2605 MOZ_CRASH(); 2606 } 2607 } 2608 } else { 2609 if (instr->bits(excl::ExclusiveOpHi, excl::ExclusiveOpLo) == 2610 excl::ExclusiveOpcode) { 2611 // Load-exclusive / store-exclusive. 2612 if (instr->bit(excl::ExclusiveLoad)) { 2613 int rn = instr->rnValue(); 2614 int rt = instr->rtValue(); 2615 int32_t address = get_register(rn); 2616 switch (instr->bits(excl::ExclusiveSizeHi, excl::ExclusiveSizeLo)) { 2617 case excl::ExclusiveWord: 2618 set_register(rt, readExW(address, instr)); 2619 break; 2620 case excl::ExclusiveDouble: { 2621 MOZ_ASSERT((rt % 2) == 0); 2622 int32_t hibits; 2623 int32_t lobits = readExDW(address, &hibits); 2624 set_register(rt, lobits); 2625 set_register(rt + 1, hibits); 2626 break; 2627 } 2628 case excl::ExclusiveByte: 2629 set_register(rt, readExBU(address)); 2630 break; 2631 case excl::ExclusiveHalf: 2632 set_register(rt, readExHU(address, instr)); 2633 break; 2634 } 2635 } else { 2636 int rn = instr->rnValue(); 2637 int rd = instr->rdValue(); 2638 int rt = instr->bits(3, 0); 2639 int32_t address = get_register(rn); 2640 int32_t value = get_register(rt); 2641 int32_t result = 0; 2642 switch (instr->bits(excl::ExclusiveSizeHi, excl::ExclusiveSizeLo)) { 2643 case excl::ExclusiveWord: 2644 result = writeExW(address, value, instr); 2645 break; 2646 case excl::ExclusiveDouble: { 2647 MOZ_ASSERT((rt % 2) == 0); 2648 int32_t value2 = get_register(rt + 1); 2649 result = writeExDW(address, value, value2); 2650 break; 2651 } 2652 case excl::ExclusiveByte: 2653 result = writeExB(address, (uint8_t)value); 2654 break; 2655 case excl::ExclusiveHalf: 2656 result = writeExH(address, (uint16_t)value, instr); 2657 break; 2658 } 2659 set_register(rd, result); 2660 } 2661 } else { 2662 MOZ_CRASH(); // Not used atm 2663 } 2664 } 2665 } else { 2666 // Extra load/store instructions. 2667 int rd = instr->rdValue(); 2668 int rn = instr->rnValue(); 2669 int32_t rn_val = get_register(rn); 2670 int32_t addr = 0; 2671 if (instr->bit(22) == 0) { 2672 int rm = instr->rmValue(); 2673 int32_t rm_val = get_register(rm); 2674 switch (instr->PUField()) { 2675 case da_x: 2676 MOZ_ASSERT(!instr->hasW()); 2677 addr = rn_val; 2678 rn_val -= rm_val; 2679 set_register(rn, rn_val); 2680 break; 2681 case ia_x: 2682 MOZ_ASSERT(!instr->hasW()); 2683 addr = rn_val; 2684 rn_val += rm_val; 2685 set_register(rn, rn_val); 2686 break; 2687 case db_x: 2688 rn_val -= rm_val; 2689 addr = rn_val; 2690 if (instr->hasW()) { 2691 set_register(rn, rn_val); 2692 } 2693 break; 2694 case ib_x: 2695 rn_val += rm_val; 2696 addr = rn_val; 2697 if (instr->hasW()) { 2698 set_register(rn, rn_val); 2699 } 2700 break; 2701 default: 2702 // The PU field is a 2-bit field. 2703 MOZ_CRASH(); 2704 break; 2705 } 2706 } else { 2707 int32_t imm_val = (instr->immedHValue() << 4) | instr->immedLValue(); 2708 switch (instr->PUField()) { 2709 case da_x: 2710 MOZ_ASSERT(!instr->hasW()); 2711 addr = rn_val; 2712 rn_val -= imm_val; 2713 set_register(rn, rn_val); 2714 break; 2715 case ia_x: 2716 MOZ_ASSERT(!instr->hasW()); 2717 addr = rn_val; 2718 rn_val += imm_val; 2719 set_register(rn, rn_val); 2720 break; 2721 case db_x: 2722 rn_val -= imm_val; 2723 addr = rn_val; 2724 if (instr->hasW()) { 2725 set_register(rn, rn_val); 2726 } 2727 break; 2728 case ib_x: 2729 rn_val += imm_val; 2730 addr = rn_val; 2731 if (instr->hasW()) { 2732 set_register(rn, rn_val); 2733 } 2734 break; 2735 default: 2736 // The PU field is a 2-bit field. 2737 MOZ_CRASH(); 2738 break; 2739 } 2740 } 2741 if ((instr->bits(7, 4) & 0xd) == 0xd && instr->bit(20) == 0) { 2742 MOZ_ASSERT((rd % 2) == 0); 2743 if (instr->hasH()) { 2744 // The strd instruction. 2745 int32_t value1 = get_register(rd); 2746 int32_t value2 = get_register(rd + 1); 2747 writeDW(addr, value1, value2); 2748 } else { 2749 // The ldrd instruction. 2750 int* rn_data = readDW(addr); 2751 if (rn_data) { 2752 set_dw_register(rd, rn_data); 2753 } 2754 } 2755 } else if (instr->hasH()) { 2756 if (instr->hasSign()) { 2757 if (instr->hasL()) { 2758 int16_t val = readH(addr, instr); 2759 set_register(rd, val); 2760 } else { 2761 int16_t val = get_register(rd); 2762 writeH(addr, val, instr); 2763 } 2764 } else { 2765 if (instr->hasL()) { 2766 uint16_t val = readHU(addr, instr); 2767 set_register(rd, val); 2768 } else { 2769 uint16_t val = get_register(rd); 2770 writeH(addr, val, instr); 2771 } 2772 } 2773 } else { 2774 // Signed byte loads. 2775 MOZ_ASSERT(instr->hasSign()); 2776 MOZ_ASSERT(instr->hasL()); 2777 int8_t val = readB(addr); 2778 set_register(rd, val); 2779 } 2780 return; 2781 } 2782 } else if ((type == 0) && instr->isMiscType0()) { 2783 if (instr->bits(7, 4) == 0) { 2784 if (instr->bit(21) == 0) { 2785 // mrs 2786 int rd = instr->rdValue(); 2787 uint32_t flags; 2788 if (instr->bit(22) == 0) { 2789 // CPSR. Note: The Q flag is not yet implemented! 2790 flags = (n_flag_ << 31) | (z_flag_ << 30) | (c_flag_ << 29) | 2791 (v_flag_ << 28); 2792 } else { 2793 // SPSR 2794 MOZ_CRASH(); 2795 } 2796 set_register(rd, flags); 2797 } else { 2798 // msr 2799 if (instr->bits(27, 23) == 2) { 2800 // Register operand. For now we only emit mask 0b1100. 2801 int rm = instr->rmValue(); 2802 mozilla::DebugOnly<uint32_t> mask = instr->bits(19, 16); 2803 MOZ_ASSERT(mask == (3 << 2)); 2804 2805 uint32_t flags = get_register(rm); 2806 n_flag_ = (flags >> 31) & 1; 2807 z_flag_ = (flags >> 30) & 1; 2808 c_flag_ = (flags >> 29) & 1; 2809 v_flag_ = (flags >> 28) & 1; 2810 } else { 2811 MOZ_CRASH(); 2812 } 2813 } 2814 } else if (instr->bits(22, 21) == 1) { 2815 int rm = instr->rmValue(); 2816 switch (instr->bits(7, 4)) { 2817 case 1: // BX 2818 set_pc(get_register(rm)); 2819 break; 2820 case 3: { // BLX 2821 uint32_t old_pc = get_pc(); 2822 set_pc(get_register(rm)); 2823 set_register(lr, old_pc + SimInstruction::kInstrSize); 2824 break; 2825 } 2826 case 7: { // BKPT 2827 fprintf(stderr, "Simulator hit BKPT.\n"); 2828 if (getenv("ARM_SIM_DEBUGGER")) { 2829 ArmDebugger dbg(this); 2830 dbg.debug(); 2831 } else { 2832 fprintf(stderr, 2833 "Use ARM_SIM_DEBUGGER=1 to enter the builtin debugger.\n"); 2834 MOZ_CRASH("ARM simulator breakpoint"); 2835 } 2836 break; 2837 } 2838 default: 2839 MOZ_CRASH(); 2840 } 2841 } else if (instr->bits(22, 21) == 3) { 2842 int rm = instr->rmValue(); 2843 int rd = instr->rdValue(); 2844 switch (instr->bits(7, 4)) { 2845 case 1: { // CLZ 2846 uint32_t bits = get_register(rm); 2847 int leading_zeros = 0; 2848 if (bits == 0) { 2849 leading_zeros = 32; 2850 } else { 2851 leading_zeros = mozilla::CountLeadingZeroes32(bits); 2852 } 2853 set_register(rd, leading_zeros); 2854 break; 2855 } 2856 default: 2857 MOZ_CRASH(); 2858 break; 2859 } 2860 } else { 2861 printf("%08x\n", instr->instructionBits()); 2862 MOZ_CRASH(); 2863 } 2864 } else if ((type == 1) && instr->isNopType1()) { 2865 // NOP. 2866 } else if ((type == 1) && instr->isYieldType1()) { 2867 AtomicOperations::pause(); 2868 } else if ((type == 1) && instr->isCsdbType1()) { 2869 // Speculation barrier. (No-op for the simulator) 2870 } else { 2871 int rd = instr->rdValue(); 2872 int rn = instr->rnValue(); 2873 // Use uint32_t here for integer overflow in operations below not to be 2874 // undefined behavior, leading to our own calculations of overflow being 2875 // messed up by the compiler. 2876 uint32_t rn_val = get_register(rn); 2877 uint32_t shifter_operand = 0; 2878 bool shifter_carry_out = 0; 2879 if (type == 0) { 2880 shifter_operand = getShiftRm(instr, &shifter_carry_out); 2881 } else { 2882 MOZ_ASSERT(instr->typeValue() == 1); 2883 shifter_operand = getImm(instr, &shifter_carry_out); 2884 } 2885 int32_t alu_out; 2886 switch (instr->opcodeField()) { 2887 case OpAnd: 2888 alu_out = rn_val & shifter_operand; 2889 set_register(rd, alu_out); 2890 if (instr->hasS()) { 2891 setNZFlags(alu_out); 2892 setCFlag(shifter_carry_out); 2893 } 2894 break; 2895 case OpEor: 2896 alu_out = rn_val ^ shifter_operand; 2897 set_register(rd, alu_out); 2898 if (instr->hasS()) { 2899 setNZFlags(alu_out); 2900 setCFlag(shifter_carry_out); 2901 } 2902 break; 2903 case OpSub: 2904 alu_out = rn_val - shifter_operand; 2905 set_register(rd, alu_out); 2906 if (instr->hasS()) { 2907 setNZFlags(alu_out); 2908 setCFlag(!borrowFrom(rn_val, shifter_operand)); 2909 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false)); 2910 } 2911 break; 2912 case OpRsb: 2913 alu_out = shifter_operand - rn_val; 2914 set_register(rd, alu_out); 2915 if (instr->hasS()) { 2916 setNZFlags(alu_out); 2917 setCFlag(!borrowFrom(shifter_operand, rn_val)); 2918 setVFlag(overflowFrom(alu_out, shifter_operand, rn_val, false)); 2919 } 2920 break; 2921 case OpAdd: 2922 alu_out = rn_val + shifter_operand; 2923 set_register(rd, alu_out); 2924 if (instr->hasS()) { 2925 setNZFlags(alu_out); 2926 setCFlag(carryFrom(rn_val, shifter_operand)); 2927 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true)); 2928 } 2929 break; 2930 case OpAdc: 2931 alu_out = rn_val + shifter_operand + getCarry(); 2932 set_register(rd, alu_out); 2933 if (instr->hasS()) { 2934 setNZFlags(alu_out); 2935 setCFlag(carryFrom(rn_val, shifter_operand, getCarry())); 2936 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true)); 2937 } 2938 break; 2939 case OpSbc: 2940 alu_out = rn_val - shifter_operand - (getCarry() == 0 ? 1 : 0); 2941 set_register(rd, alu_out); 2942 if (instr->hasS()) { 2943 MOZ_CRASH(); 2944 } 2945 break; 2946 case OpRsc: 2947 alu_out = shifter_operand - rn_val - (getCarry() == 0 ? 1 : 0); 2948 set_register(rd, alu_out); 2949 if (instr->hasS()) { 2950 MOZ_CRASH(); 2951 } 2952 break; 2953 case OpTst: 2954 if (instr->hasS()) { 2955 alu_out = rn_val & shifter_operand; 2956 setNZFlags(alu_out); 2957 setCFlag(shifter_carry_out); 2958 } else { 2959 alu_out = instr->immedMovwMovtValue(); 2960 set_register(rd, alu_out); 2961 } 2962 break; 2963 case OpTeq: 2964 if (instr->hasS()) { 2965 alu_out = rn_val ^ shifter_operand; 2966 setNZFlags(alu_out); 2967 setCFlag(shifter_carry_out); 2968 } else { 2969 // Other instructions matching this pattern are handled in the 2970 // miscellaneous instructions part above. 2971 MOZ_CRASH(); 2972 } 2973 break; 2974 case OpCmp: 2975 if (instr->hasS()) { 2976 alu_out = rn_val - shifter_operand; 2977 setNZFlags(alu_out); 2978 setCFlag(!borrowFrom(rn_val, shifter_operand)); 2979 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false)); 2980 } else { 2981 alu_out = 2982 (get_register(rd) & 0xffff) | (instr->immedMovwMovtValue() << 16); 2983 set_register(rd, alu_out); 2984 } 2985 break; 2986 case OpCmn: 2987 if (instr->hasS()) { 2988 alu_out = rn_val + shifter_operand; 2989 setNZFlags(alu_out); 2990 setCFlag(carryFrom(rn_val, shifter_operand)); 2991 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true)); 2992 } else { 2993 // Other instructions matching this pattern are handled in the 2994 // miscellaneous instructions part above. 2995 MOZ_CRASH(); 2996 } 2997 break; 2998 case OpOrr: 2999 alu_out = rn_val | shifter_operand; 3000 set_register(rd, alu_out); 3001 if (instr->hasS()) { 3002 setNZFlags(alu_out); 3003 setCFlag(shifter_carry_out); 3004 } 3005 break; 3006 case OpMov: 3007 alu_out = shifter_operand; 3008 set_register(rd, alu_out); 3009 if (instr->hasS()) { 3010 setNZFlags(alu_out); 3011 setCFlag(shifter_carry_out); 3012 } 3013 break; 3014 case OpBic: 3015 alu_out = rn_val & ~shifter_operand; 3016 set_register(rd, alu_out); 3017 if (instr->hasS()) { 3018 setNZFlags(alu_out); 3019 setCFlag(shifter_carry_out); 3020 } 3021 break; 3022 case OpMvn: 3023 alu_out = ~shifter_operand; 3024 set_register(rd, alu_out); 3025 if (instr->hasS()) { 3026 setNZFlags(alu_out); 3027 setCFlag(shifter_carry_out); 3028 } 3029 break; 3030 default: 3031 MOZ_CRASH(); 3032 break; 3033 } 3034 } 3035 } 3036 3037 void Simulator::decodeType2(SimInstruction* instr) { 3038 int rd = instr->rdValue(); 3039 int rn = instr->rnValue(); 3040 int32_t rn_val = get_register(rn); 3041 int32_t im_val = instr->offset12Value(); 3042 int32_t addr = 0; 3043 switch (instr->PUField()) { 3044 case da_x: 3045 MOZ_ASSERT(!instr->hasW()); 3046 addr = rn_val; 3047 rn_val -= im_val; 3048 set_register(rn, rn_val); 3049 break; 3050 case ia_x: 3051 MOZ_ASSERT(!instr->hasW()); 3052 addr = rn_val; 3053 rn_val += im_val; 3054 set_register(rn, rn_val); 3055 break; 3056 case db_x: 3057 rn_val -= im_val; 3058 addr = rn_val; 3059 if (instr->hasW()) { 3060 set_register(rn, rn_val); 3061 } 3062 break; 3063 case ib_x: 3064 rn_val += im_val; 3065 addr = rn_val; 3066 if (instr->hasW()) { 3067 set_register(rn, rn_val); 3068 } 3069 break; 3070 default: 3071 MOZ_CRASH(); 3072 break; 3073 } 3074 if (instr->hasB()) { 3075 if (instr->hasL()) { 3076 uint8_t val = readBU(addr); 3077 set_register(rd, val); 3078 } else { 3079 uint8_t val = get_register(rd); 3080 writeB(addr, val); 3081 } 3082 } else { 3083 if (instr->hasL()) { 3084 set_register(rd, readW(addr, instr, AllowUnaligned)); 3085 } else { 3086 writeW(addr, get_register(rd), instr, AllowUnaligned); 3087 } 3088 } 3089 } 3090 3091 static uint32_t rotateBytes(uint32_t val, int32_t rotate) { 3092 switch (rotate) { 3093 default: 3094 return val; 3095 case 1: 3096 return (val >> 8) | (val << 24); 3097 case 2: 3098 return (val >> 16) | (val << 16); 3099 case 3: 3100 return (val >> 24) | (val << 8); 3101 } 3102 } 3103 3104 void Simulator::decodeType3(SimInstruction* instr) { 3105 if (MOZ_UNLIKELY(instr->isUDF())) { 3106 uint8_t* newPC; 3107 if (wasm::HandleIllegalInstruction(registerState(), &newPC)) { 3108 set_pc((int32_t)newPC); 3109 return; 3110 } 3111 MOZ_CRASH("illegal instruction encountered"); 3112 } 3113 3114 int rd = instr->rdValue(); 3115 int rn = instr->rnValue(); 3116 int32_t rn_val = get_register(rn); 3117 bool shifter_carry_out = 0; 3118 int32_t shifter_operand = getShiftRm(instr, &shifter_carry_out); 3119 int32_t addr = 0; 3120 switch (instr->PUField()) { 3121 case da_x: 3122 MOZ_ASSERT(!instr->hasW()); 3123 MOZ_CRASH(); 3124 break; 3125 case ia_x: { 3126 if (instr->bit(4) == 0) { 3127 // Memop. 3128 } else { 3129 if (instr->bit(5) == 0) { 3130 switch (instr->bits(22, 21)) { 3131 case 0: 3132 if (instr->bit(20) == 0) { 3133 if (instr->bit(6) == 0) { 3134 // Pkhbt. 3135 uint32_t rn_val = get_register(rn); 3136 uint32_t rm_val = get_register(instr->rmValue()); 3137 int32_t shift = instr->bits(11, 7); 3138 rm_val <<= shift; 3139 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U)); 3140 } else { 3141 // Pkhtb. 3142 uint32_t rn_val = get_register(rn); 3143 int32_t rm_val = get_register(instr->rmValue()); 3144 int32_t shift = instr->bits(11, 7); 3145 if (shift == 0) { 3146 shift = 32; 3147 } 3148 rm_val >>= shift; 3149 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF)); 3150 } 3151 } else { 3152 MOZ_CRASH(); 3153 } 3154 break; 3155 case 1: 3156 MOZ_CRASH(); 3157 break; 3158 case 2: 3159 MOZ_CRASH(); 3160 break; 3161 case 3: { 3162 // Usat. 3163 int32_t sat_pos = instr->bits(20, 16); 3164 int32_t sat_val = (1 << sat_pos) - 1; 3165 int32_t shift = instr->bits(11, 7); 3166 int32_t shift_type = instr->bit(6); 3167 int32_t rm_val = get_register(instr->rmValue()); 3168 if (shift_type == 0) { // LSL 3169 rm_val <<= shift; 3170 } else { // ASR 3171 rm_val >>= shift; 3172 } 3173 3174 // If saturation occurs, the Q flag should be set in the 3175 // CPSR. There is no Q flag yet, and no instruction (MRS) 3176 // to read the CPSR directly. 3177 if (rm_val > sat_val) { 3178 rm_val = sat_val; 3179 } else if (rm_val < 0) { 3180 rm_val = 0; 3181 } 3182 set_register(rd, rm_val); 3183 break; 3184 } 3185 } 3186 } else { 3187 switch (instr->bits(22, 21)) { 3188 case 0: 3189 MOZ_CRASH(); 3190 break; 3191 case 1: 3192 if (instr->bits(7, 4) == 7 && instr->bits(19, 16) == 15) { 3193 uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), 3194 instr->bits(11, 10)); 3195 if (instr->bit(20)) { 3196 // Sxth. 3197 set_register(rd, (int32_t)(int16_t)(rm_val & 0xFFFF)); 3198 } else { 3199 // Sxtb. 3200 set_register(rd, (int32_t)(int8_t)(rm_val & 0xFF)); 3201 } 3202 } else if (instr->bits(20, 16) == 0b1'1111 && 3203 instr->bits(11, 4) == 0b1111'0011) { 3204 // Rev 3205 uint32_t rm_val = get_register(instr->rmValue()); 3206 3207 static_assert(MOZ_LITTLE_ENDIAN()); 3208 set_register(rd, 3209 mozilla::NativeEndian::swapToBigEndian(rm_val)); 3210 } else if (instr->bits(20, 16) == 0b1'1111 && 3211 instr->bits(11, 4) == 0b1111'1011) { 3212 // Rev16 3213 uint32_t rm_val = get_register(instr->rmValue()); 3214 3215 static_assert(MOZ_LITTLE_ENDIAN()); 3216 uint32_t hi = mozilla::NativeEndian::swapToBigEndian( 3217 uint16_t(rm_val >> 16)); 3218 uint32_t lo = 3219 mozilla::NativeEndian::swapToBigEndian(uint16_t(rm_val)); 3220 set_register(rd, (hi << 16) | lo); 3221 } else { 3222 MOZ_CRASH(); 3223 } 3224 break; 3225 case 2: 3226 if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) { 3227 if (instr->bits(19, 16) == 0xF) { 3228 // Uxtb16. 3229 uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), 3230 instr->bits(11, 10)); 3231 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000)); 3232 } else { 3233 MOZ_CRASH(); 3234 } 3235 } else { 3236 MOZ_CRASH(); 3237 } 3238 break; 3239 case 3: 3240 if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) { 3241 if (instr->bits(19, 16) == 0xF) { 3242 // Uxtb. 3243 uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), 3244 instr->bits(11, 10)); 3245 set_register(rd, (rm_val & 0xFF)); 3246 } else { 3247 // Uxtab. 3248 uint32_t rn_val = get_register(rn); 3249 uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), 3250 instr->bits(11, 10)); 3251 set_register(rd, rn_val + (rm_val & 0xFF)); 3252 } 3253 } else if ((instr->bit(20) == 1) && (instr->bits(9, 6) == 1)) { 3254 if (instr->bits(19, 16) == 0xF) { 3255 // Uxth. 3256 uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), 3257 instr->bits(11, 10)); 3258 set_register(rd, (rm_val & 0xFFFF)); 3259 } else { 3260 // Uxtah. 3261 uint32_t rn_val = get_register(rn); 3262 uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), 3263 instr->bits(11, 10)); 3264 set_register(rd, rn_val + (rm_val & 0xFFFF)); 3265 } 3266 } else if (instr->bits(20, 16) == 0b1'1111 && 3267 instr->bits(11, 4) == 0b1111'1011) { 3268 // Revsh 3269 uint32_t rm_val = get_register(instr->rmValue()); 3270 3271 static_assert(MOZ_LITTLE_ENDIAN()); 3272 set_register( 3273 rd, int32_t(int16_t(mozilla::NativeEndian::swapToBigEndian( 3274 uint16_t(rm_val))))); 3275 } else { 3276 MOZ_CRASH(); 3277 } 3278 break; 3279 } 3280 } 3281 return; 3282 } 3283 break; 3284 } 3285 case db_x: { // sudiv 3286 if (instr->bit(22) == 0x0 && instr->bit(20) == 0x1 && 3287 instr->bits(15, 12) == 0x0f && instr->bits(7, 4) == 0x1) { 3288 if (!instr->hasW()) { 3289 // sdiv (in V8 notation matching ARM ISA format) rn = rm/rs. 3290 int rm = instr->rmValue(); 3291 int32_t rm_val = get_register(rm); 3292 int rs = instr->rsValue(); 3293 int32_t rs_val = get_register(rs); 3294 int32_t ret_val = 0; 3295 MOZ_ASSERT(rs_val != 0); 3296 if ((rm_val == INT32_MIN) && (rs_val == -1)) { 3297 ret_val = INT32_MIN; 3298 } else { 3299 ret_val = rm_val / rs_val; 3300 } 3301 set_register(rn, ret_val); 3302 return; 3303 } else { 3304 // udiv (in V8 notation matching ARM ISA format) rn = rm/rs. 3305 int rm = instr->rmValue(); 3306 uint32_t rm_val = get_register(rm); 3307 int rs = instr->rsValue(); 3308 uint32_t rs_val = get_register(rs); 3309 uint32_t ret_val = 0; 3310 MOZ_ASSERT(rs_val != 0); 3311 ret_val = rm_val / rs_val; 3312 set_register(rn, ret_val); 3313 return; 3314 } 3315 } 3316 3317 addr = rn_val - shifter_operand; 3318 if (instr->hasW()) { 3319 set_register(rn, addr); 3320 } 3321 break; 3322 } 3323 case ib_x: { 3324 if (instr->hasW() && (instr->bits(6, 4) == 0x5)) { 3325 uint32_t widthminus1 = static_cast<uint32_t>(instr->bits(20, 16)); 3326 uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7)); 3327 uint32_t msbit = widthminus1 + lsbit; 3328 if (msbit <= 31) { 3329 if (instr->bit(22)) { 3330 // ubfx - unsigned bitfield extract. 3331 uint32_t rm_val = 3332 static_cast<uint32_t>(get_register(instr->rmValue())); 3333 uint32_t extr_val = rm_val << (31 - msbit); 3334 extr_val = extr_val >> (31 - widthminus1); 3335 set_register(instr->rdValue(), extr_val); 3336 } else { 3337 // sbfx - signed bitfield extract. 3338 int32_t rm_val = get_register(instr->rmValue()); 3339 int32_t extr_val = rm_val << (31 - msbit); 3340 extr_val = extr_val >> (31 - widthminus1); 3341 set_register(instr->rdValue(), extr_val); 3342 } 3343 } else { 3344 MOZ_CRASH(); 3345 } 3346 return; 3347 } else if (!instr->hasW() && (instr->bits(6, 4) == 0x1)) { 3348 uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7)); 3349 uint32_t msbit = static_cast<uint32_t>(instr->bits(20, 16)); 3350 if (msbit >= lsbit) { 3351 // bfc or bfi - bitfield clear/insert. 3352 uint32_t rd_val = 3353 static_cast<uint32_t>(get_register(instr->rdValue())); 3354 uint32_t bitcount = msbit - lsbit + 1; 3355 uint32_t mask = (1 << bitcount) - 1; 3356 rd_val &= ~(mask << lsbit); 3357 if (instr->rmValue() != 15) { 3358 // bfi - bitfield insert. 3359 uint32_t rm_val = 3360 static_cast<uint32_t>(get_register(instr->rmValue())); 3361 rm_val &= mask; 3362 rd_val |= rm_val << lsbit; 3363 } 3364 set_register(instr->rdValue(), rd_val); 3365 } else { 3366 MOZ_CRASH(); 3367 } 3368 return; 3369 } else { 3370 addr = rn_val + shifter_operand; 3371 if (instr->hasW()) { 3372 set_register(rn, addr); 3373 } 3374 } 3375 break; 3376 } 3377 default: 3378 MOZ_CRASH(); 3379 break; 3380 } 3381 if (instr->hasB()) { 3382 if (instr->hasL()) { 3383 uint8_t byte = readB(addr); 3384 set_register(rd, byte); 3385 } else { 3386 uint8_t byte = get_register(rd); 3387 writeB(addr, byte); 3388 } 3389 } else { 3390 if (instr->hasL()) { 3391 set_register(rd, readW(addr, instr, AllowUnaligned)); 3392 } else { 3393 writeW(addr, get_register(rd), instr, AllowUnaligned); 3394 } 3395 } 3396 } 3397 3398 void Simulator::decodeType4(SimInstruction* instr) { 3399 // Only allowed to be set in privileged mode. 3400 MOZ_ASSERT(instr->bit(22) == 0); 3401 bool load = instr->hasL(); 3402 handleRList(instr, load); 3403 } 3404 3405 void Simulator::decodeType5(SimInstruction* instr) { 3406 int off = instr->sImmed24Value() << 2; 3407 intptr_t pc_address = get_pc(); 3408 if (instr->hasLink()) { 3409 set_register(lr, pc_address + SimInstruction::kInstrSize); 3410 } 3411 int pc_reg = get_register(pc); 3412 set_pc(pc_reg + off); 3413 } 3414 3415 void Simulator::decodeType6(SimInstruction* instr) { 3416 decodeType6CoprocessorIns(instr); 3417 } 3418 3419 void Simulator::decodeType7(SimInstruction* instr) { 3420 if (instr->bit(24) == 1) { 3421 softwareInterrupt(instr); 3422 } else if (instr->bit(4) == 1 && instr->bits(11, 9) != 5) { 3423 decodeType7CoprocessorIns(instr); 3424 } else { 3425 decodeTypeVFP(instr); 3426 } 3427 } 3428 3429 void Simulator::decodeType7CoprocessorIns(SimInstruction* instr) { 3430 if (instr->bit(20) == 0) { 3431 // MCR, MCR2 3432 if (instr->coprocessorValue() == 15) { 3433 int opc1 = instr->bits(23, 21); 3434 int opc2 = instr->bits(7, 5); 3435 int CRn = instr->bits(19, 16); 3436 int CRm = instr->bits(3, 0); 3437 if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 10) { 3438 // ARMv6 DSB instruction. We do not use DSB. 3439 MOZ_CRASH("DSB not implemented"); 3440 } else if (opc1 == 0 && opc2 == 5 && CRn == 7 && CRm == 10) { 3441 // ARMv6 DMB instruction. 3442 AtomicOperations::fenceSeqCst(); 3443 } else if (opc1 == 0 && opc2 == 4 && CRn == 7 && CRm == 5) { 3444 // ARMv6 ISB instruction. We do not use ISB. 3445 MOZ_CRASH("ISB not implemented"); 3446 } else { 3447 MOZ_CRASH(); 3448 } 3449 } else { 3450 MOZ_CRASH(); 3451 } 3452 } else { 3453 // MRC, MRC2 3454 MOZ_CRASH(); 3455 } 3456 } 3457 3458 void Simulator::decodeTypeVFP(SimInstruction* instr) { 3459 MOZ_ASSERT(instr->typeValue() == 7 && instr->bit(24) == 0); 3460 MOZ_ASSERT(instr->bits(11, 9) == 0x5); 3461 3462 // Obtain double precision register codes. 3463 VFPRegPrecision precision = 3464 (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision; 3465 int vm = instr->VFPMRegValue(precision); 3466 int vd = instr->VFPDRegValue(precision); 3467 int vn = instr->VFPNRegValue(precision); 3468 3469 if (instr->bit(4) == 0) { 3470 if (instr->opc1Value() == 0x7) { 3471 // Other data processing instructions. 3472 if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x1)) { 3473 // vmov register to register. 3474 if (instr->szValue() == 0x1) { 3475 int m = instr->VFPMRegValue(kDoublePrecision); 3476 int d = instr->VFPDRegValue(kDoublePrecision); 3477 double temp; 3478 get_double_from_d_register(m, &temp); 3479 set_d_register_from_double(d, temp); 3480 } else { 3481 int m = instr->VFPMRegValue(kSinglePrecision); 3482 int d = instr->VFPDRegValue(kSinglePrecision); 3483 float temp; 3484 get_float_from_s_register(m, &temp); 3485 set_s_register_from_float(d, temp); 3486 } 3487 } else if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x3)) { 3488 // vabs 3489 if (instr->szValue() == 0x1) { 3490 union { 3491 double f64; 3492 uint64_t u64; 3493 } u; 3494 get_double_from_d_register(vm, &u.f64); 3495 u.u64 &= 0x7fffffffffffffffu; 3496 double dd_value = u.f64; 3497 canonicalizeNaN(&dd_value); 3498 set_d_register_from_double(vd, dd_value); 3499 } else { 3500 union { 3501 float f32; 3502 uint32_t u32; 3503 } u; 3504 get_float_from_s_register(vm, &u.f32); 3505 u.u32 &= 0x7fffffffu; 3506 float fd_value = u.f32; 3507 canonicalizeNaN(&fd_value); 3508 set_s_register_from_float(vd, fd_value); 3509 } 3510 } else if ((instr->opc2Value() == 0x1) && (instr->opc3Value() == 0x1)) { 3511 // vneg 3512 if (instr->szValue() == 0x1) { 3513 double dm_value; 3514 get_double_from_d_register(vm, &dm_value); 3515 double dd_value = -dm_value; 3516 canonicalizeNaN(&dd_value); 3517 set_d_register_from_double(vd, dd_value); 3518 } else { 3519 float fm_value; 3520 get_float_from_s_register(vm, &fm_value); 3521 float fd_value = -fm_value; 3522 canonicalizeNaN(&fd_value); 3523 set_s_register_from_float(vd, fd_value); 3524 } 3525 } else if ((instr->opc2Value() == 0x7) && (instr->opc3Value() == 0x3)) { 3526 decodeVCVTBetweenDoubleAndSingle(instr); 3527 } else if ((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) { 3528 decodeVCVTBetweenFloatingPointAndInteger(instr); 3529 } else if ((instr->opc2Value() == 0xA) && (instr->opc3Value() == 0x3) && 3530 (instr->bit(8) == 1)) { 3531 // vcvt.f64.s32 Dd, Dd, #<fbits>. 3532 int fraction_bits = 32 - ((instr->bits(3, 0) << 1) | instr->bit(5)); 3533 int fixed_value = get_sinteger_from_s_register(vd * 2); 3534 double divide = 1 << fraction_bits; 3535 set_d_register_from_double(vd, fixed_value / divide); 3536 } else if (((instr->opc2Value() >> 1) == 0x6) && 3537 (instr->opc3Value() & 0x1)) { 3538 decodeVCVTBetweenFloatingPointAndInteger(instr); 3539 } else if (((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) && 3540 (instr->opc3Value() & 0x1)) { 3541 decodeVCMP(instr); 3542 } else if (((instr->opc2Value() == 0x1)) && (instr->opc3Value() == 0x3)) { 3543 // vsqrt 3544 if (instr->szValue() == 0x1) { 3545 double dm_value; 3546 get_double_from_d_register(vm, &dm_value); 3547 double dd_value = std::sqrt(dm_value); 3548 canonicalizeNaN(&dd_value); 3549 set_d_register_from_double(vd, dd_value); 3550 } else { 3551 float fm_value; 3552 get_float_from_s_register(vm, &fm_value); 3553 float fd_value = std::sqrt(fm_value); 3554 canonicalizeNaN(&fd_value); 3555 set_s_register_from_float(vd, fd_value); 3556 } 3557 } else if (instr->opc3Value() == 0x0) { 3558 // vmov immediate. 3559 if (instr->szValue() == 0x1) { 3560 set_d_register_from_double(vd, instr->doubleImmedVmov()); 3561 } else { 3562 // vmov.f32 immediate. 3563 set_s_register_from_float(vd, instr->float32ImmedVmov()); 3564 } 3565 } else if ((instr->opc2Value() & ~0x1) == 0x2 && 3566 (instr->opc3Value() & 0x1)) { 3567 decodeVCVTBetweenFloatingPointAndHalf(instr); 3568 } else { 3569 decodeVCVTBetweenFloatingPointAndIntegerFrac(instr); 3570 } 3571 } else if (instr->opc1Value() == 0x3) { 3572 if (instr->szValue() != 0x1) { 3573 if (instr->opc3Value() & 0x1) { 3574 // vsub 3575 float fn_value; 3576 get_float_from_s_register(vn, &fn_value); 3577 float fm_value; 3578 get_float_from_s_register(vm, &fm_value); 3579 float fd_value = fn_value - fm_value; 3580 canonicalizeNaN(&fd_value); 3581 set_s_register_from_float(vd, fd_value); 3582 } else { 3583 // vadd 3584 float fn_value; 3585 get_float_from_s_register(vn, &fn_value); 3586 float fm_value; 3587 get_float_from_s_register(vm, &fm_value); 3588 float fd_value = fn_value + fm_value; 3589 canonicalizeNaN(&fd_value); 3590 set_s_register_from_float(vd, fd_value); 3591 } 3592 } else { 3593 if (instr->opc3Value() & 0x1) { 3594 // vsub 3595 double dn_value; 3596 get_double_from_d_register(vn, &dn_value); 3597 double dm_value; 3598 get_double_from_d_register(vm, &dm_value); 3599 double dd_value = dn_value - dm_value; 3600 canonicalizeNaN(&dd_value); 3601 set_d_register_from_double(vd, dd_value); 3602 } else { 3603 // vadd 3604 double dn_value; 3605 get_double_from_d_register(vn, &dn_value); 3606 double dm_value; 3607 get_double_from_d_register(vm, &dm_value); 3608 double dd_value = dn_value + dm_value; 3609 canonicalizeNaN(&dd_value); 3610 set_d_register_from_double(vd, dd_value); 3611 } 3612 } 3613 } else if ((instr->opc1Value() == 0x2) && !(instr->opc3Value() & 0x1)) { 3614 // vmul 3615 if (instr->szValue() != 0x1) { 3616 float fn_value; 3617 get_float_from_s_register(vn, &fn_value); 3618 float fm_value; 3619 get_float_from_s_register(vm, &fm_value); 3620 float fd_value = fn_value * fm_value; 3621 canonicalizeNaN(&fd_value); 3622 set_s_register_from_float(vd, fd_value); 3623 } else { 3624 double dn_value; 3625 get_double_from_d_register(vn, &dn_value); 3626 double dm_value; 3627 get_double_from_d_register(vm, &dm_value); 3628 double dd_value = dn_value * dm_value; 3629 canonicalizeNaN(&dd_value); 3630 set_d_register_from_double(vd, dd_value); 3631 } 3632 } else if ((instr->opc1Value() == 0x0)) { 3633 // vmla, vmls 3634 const bool is_vmls = (instr->opc3Value() & 0x1); 3635 3636 if (instr->szValue() != 0x1) { 3637 MOZ_CRASH("Not used by V8."); 3638 } 3639 3640 double dd_val; 3641 get_double_from_d_register(vd, &dd_val); 3642 double dn_val; 3643 get_double_from_d_register(vn, &dn_val); 3644 double dm_val; 3645 get_double_from_d_register(vm, &dm_val); 3646 3647 // Note: we do the mul and add/sub in separate steps to avoid 3648 // getting a result with too high precision. 3649 set_d_register_from_double(vd, dn_val * dm_val); 3650 double temp; 3651 get_double_from_d_register(vd, &temp); 3652 if (is_vmls) { 3653 temp = dd_val - temp; 3654 } else { 3655 temp = dd_val + temp; 3656 } 3657 canonicalizeNaN(&temp); 3658 set_d_register_from_double(vd, temp); 3659 } else if ((instr->opc1Value() == 0x4) && !(instr->opc3Value() & 0x1)) { 3660 // vdiv 3661 if (instr->szValue() != 0x1) { 3662 float fn_value; 3663 get_float_from_s_register(vn, &fn_value); 3664 float fm_value; 3665 get_float_from_s_register(vm, &fm_value); 3666 float fd_value = fn_value / fm_value; 3667 div_zero_vfp_flag_ = (fm_value == 0); 3668 canonicalizeNaN(&fd_value); 3669 set_s_register_from_float(vd, fd_value); 3670 } else { 3671 double dn_value; 3672 get_double_from_d_register(vn, &dn_value); 3673 double dm_value; 3674 get_double_from_d_register(vm, &dm_value); 3675 double dd_value = dn_value / dm_value; 3676 div_zero_vfp_flag_ = (dm_value == 0); 3677 canonicalizeNaN(&dd_value); 3678 set_d_register_from_double(vd, dd_value); 3679 } 3680 } else { 3681 MOZ_CRASH(); 3682 } 3683 } else { 3684 if (instr->VCValue() == 0x0 && instr->VAValue() == 0x0) { 3685 decodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr); 3686 } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x1) && 3687 (instr->bit(23) == 0x0)) { 3688 // vmov (ARM core register to scalar). 3689 int vd = instr->bits(19, 16) | (instr->bit(7) << 4); 3690 double dd_value; 3691 get_double_from_d_register(vd, &dd_value); 3692 int32_t data[2]; 3693 memcpy(data, &dd_value, 8); 3694 data[instr->bit(21)] = get_register(instr->rtValue()); 3695 memcpy(&dd_value, data, 8); 3696 set_d_register_from_double(vd, dd_value); 3697 } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x1) && 3698 (instr->bit(23) == 0x0)) { 3699 // vmov (scalar to ARM core register). 3700 int vn = instr->bits(19, 16) | (instr->bit(7) << 4); 3701 double dn_value; 3702 get_double_from_d_register(vn, &dn_value); 3703 int32_t data[2]; 3704 memcpy(data, &dn_value, 8); 3705 set_register(instr->rtValue(), data[instr->bit(21)]); 3706 } else if ((instr->VLValue() == 0x1) && (instr->VCValue() == 0x0) && 3707 (instr->VAValue() == 0x7) && (instr->bits(19, 16) == 0x1)) { 3708 // vmrs 3709 uint32_t rt = instr->rtValue(); 3710 if (rt == 0xF) { 3711 copy_FPSCR_to_APSR(); 3712 } else { 3713 // Emulate FPSCR from the Simulator flags. 3714 uint32_t fpscr = (n_flag_FPSCR_ << 31) | (z_flag_FPSCR_ << 30) | 3715 (c_flag_FPSCR_ << 29) | (v_flag_FPSCR_ << 28) | 3716 (FPSCR_default_NaN_mode_ << 25) | 3717 (inexact_vfp_flag_ << 4) | (underflow_vfp_flag_ << 3) | 3718 (overflow_vfp_flag_ << 2) | (div_zero_vfp_flag_ << 1) | 3719 (inv_op_vfp_flag_ << 0) | (FPSCR_rounding_mode_); 3720 set_register(rt, fpscr); 3721 } 3722 } else if ((instr->VLValue() == 0x0) && (instr->VCValue() == 0x0) && 3723 (instr->VAValue() == 0x7) && (instr->bits(19, 16) == 0x1)) { 3724 // vmsr 3725 uint32_t rt = instr->rtValue(); 3726 if (rt == pc) { 3727 MOZ_CRASH(); 3728 } else { 3729 uint32_t rt_value = get_register(rt); 3730 n_flag_FPSCR_ = (rt_value >> 31) & 1; 3731 z_flag_FPSCR_ = (rt_value >> 30) & 1; 3732 c_flag_FPSCR_ = (rt_value >> 29) & 1; 3733 v_flag_FPSCR_ = (rt_value >> 28) & 1; 3734 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1; 3735 inexact_vfp_flag_ = (rt_value >> 4) & 1; 3736 underflow_vfp_flag_ = (rt_value >> 3) & 1; 3737 overflow_vfp_flag_ = (rt_value >> 2) & 1; 3738 div_zero_vfp_flag_ = (rt_value >> 1) & 1; 3739 inv_op_vfp_flag_ = (rt_value >> 0) & 1; 3740 FPSCR_rounding_mode_ = 3741 static_cast<VFPRoundingMode>((rt_value)&kVFPRoundingModeMask); 3742 } 3743 } else { 3744 MOZ_CRASH(); 3745 } 3746 } 3747 } 3748 3749 void Simulator::decodeVMOVBetweenCoreAndSinglePrecisionRegisters( 3750 SimInstruction* instr) { 3751 MOZ_ASSERT(instr->bit(4) == 1 && instr->VCValue() == 0x0 && 3752 instr->VAValue() == 0x0); 3753 3754 int t = instr->rtValue(); 3755 int n = instr->VFPNRegValue(kSinglePrecision); 3756 bool to_arm_register = (instr->VLValue() == 0x1); 3757 if (to_arm_register) { 3758 int32_t int_value = get_sinteger_from_s_register(n); 3759 set_register(t, int_value); 3760 } else { 3761 int32_t rs_val = get_register(t); 3762 set_s_register_from_sinteger(n, rs_val); 3763 } 3764 } 3765 3766 void Simulator::decodeVCMP(SimInstruction* instr) { 3767 MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7)); 3768 MOZ_ASSERT(((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) && 3769 (instr->opc3Value() & 0x1)); 3770 // Comparison. 3771 3772 VFPRegPrecision precision = kSinglePrecision; 3773 if (instr->szValue() == 1) { 3774 precision = kDoublePrecision; 3775 } 3776 3777 int d = instr->VFPDRegValue(precision); 3778 int m = 0; 3779 if (instr->opc2Value() == 0x4) { 3780 m = instr->VFPMRegValue(precision); 3781 } 3782 3783 if (precision == kDoublePrecision) { 3784 double dd_value; 3785 get_double_from_d_register(d, &dd_value); 3786 double dm_value = 0.0; 3787 if (instr->opc2Value() == 0x4) { 3788 get_double_from_d_register(m, &dm_value); 3789 } 3790 3791 // Raise exceptions for quiet NaNs if necessary. 3792 if (instr->bit(7) == 1) { 3793 if (std::isnan(dd_value)) { 3794 inv_op_vfp_flag_ = true; 3795 } 3796 } 3797 compute_FPSCR_Flags(dd_value, dm_value); 3798 } else { 3799 float fd_value; 3800 get_float_from_s_register(d, &fd_value); 3801 float fm_value = 0.0; 3802 if (instr->opc2Value() == 0x4) { 3803 get_float_from_s_register(m, &fm_value); 3804 } 3805 3806 // Raise exceptions for quiet NaNs if necessary. 3807 if (instr->bit(7) == 1) { 3808 if (std::isnan(fd_value)) { 3809 inv_op_vfp_flag_ = true; 3810 } 3811 } 3812 compute_FPSCR_Flags(fd_value, fm_value); 3813 } 3814 } 3815 3816 void Simulator::decodeVCVTBetweenDoubleAndSingle(SimInstruction* instr) { 3817 MOZ_ASSERT(instr->bit(4) == 0 && instr->opc1Value() == 0x7); 3818 MOZ_ASSERT(instr->opc2Value() == 0x7 && instr->opc3Value() == 0x3); 3819 3820 VFPRegPrecision dst_precision = kDoublePrecision; 3821 VFPRegPrecision src_precision = kSinglePrecision; 3822 if (instr->szValue() == 1) { 3823 dst_precision = kSinglePrecision; 3824 src_precision = kDoublePrecision; 3825 } 3826 3827 int dst = instr->VFPDRegValue(dst_precision); 3828 int src = instr->VFPMRegValue(src_precision); 3829 3830 if (dst_precision == kSinglePrecision) { 3831 double val; 3832 get_double_from_d_register(src, &val); 3833 set_s_register_from_float(dst, static_cast<float>(val)); 3834 } else { 3835 float val; 3836 get_float_from_s_register(src, &val); 3837 set_d_register_from_double(dst, static_cast<double>(val)); 3838 } 3839 } 3840 3841 static bool get_inv_op_vfp_flag(VFPRoundingMode mode, double val, 3842 bool unsigned_) { 3843 MOZ_ASSERT(mode == SimRN || mode == SimRM || mode == SimRZ); 3844 double max_uint = static_cast<double>(0xffffffffu); 3845 double max_int = static_cast<double>(INT32_MAX); 3846 double min_int = static_cast<double>(INT32_MIN); 3847 3848 // Check for NaN. 3849 if (val != val) { 3850 return true; 3851 } 3852 3853 // Check for overflow. This code works because 32bit integers can be exactly 3854 // represented by ieee-754 64bit floating-point values. 3855 switch (mode) { 3856 case SimRN: 3857 return unsigned_ ? (val >= (max_uint + 0.5)) || (val < -0.5) 3858 : (val >= (max_int + 0.5)) || (val < (min_int - 0.5)); 3859 case SimRM: 3860 return unsigned_ ? (val >= (max_uint + 1.0)) || (val < 0) 3861 : (val >= (max_int + 1.0)) || (val < min_int); 3862 case SimRZ: 3863 return unsigned_ ? (val >= (max_uint + 1.0)) || (val <= -1) 3864 : (val >= (max_int + 1.0)) || (val <= (min_int - 1.0)); 3865 default: 3866 MOZ_CRASH(); 3867 return true; 3868 } 3869 } 3870 3871 // We call this function only if we had a vfp invalid exception. 3872 // It returns the correct saturated value. 3873 static int VFPConversionSaturate(double val, bool unsigned_res) { 3874 if (val != val) { // NaN. 3875 return 0; 3876 } 3877 if (unsigned_res) { 3878 return (val < 0) ? 0 : 0xffffffffu; 3879 } 3880 return (val < 0) ? INT32_MIN : INT32_MAX; 3881 } 3882 3883 void Simulator::decodeVCVTBetweenFloatingPointAndInteger( 3884 SimInstruction* instr) { 3885 MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7) && 3886 (instr->bits(27, 23) == 0x1D)); 3887 MOZ_ASSERT( 3888 ((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) || 3889 (((instr->opc2Value() >> 1) == 0x6) && (instr->opc3Value() & 0x1))); 3890 3891 // Conversion between floating-point and integer. 3892 bool to_integer = (instr->bit(18) == 1); 3893 3894 VFPRegPrecision src_precision = 3895 (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision; 3896 3897 if (to_integer) { 3898 // We are playing with code close to the C++ standard's limits below, 3899 // hence the very simple code and heavy checks. 3900 // 3901 // Note: C++ defines default type casting from floating point to integer 3902 // as (close to) rounding toward zero ("fractional part discarded"). 3903 3904 int dst = instr->VFPDRegValue(kSinglePrecision); 3905 int src = instr->VFPMRegValue(src_precision); 3906 3907 // Bit 7 in vcvt instructions indicates if we should use the FPSCR 3908 // rounding mode or the default Round to Zero mode. 3909 VFPRoundingMode mode = (instr->bit(7) != 1) ? FPSCR_rounding_mode_ : SimRZ; 3910 MOZ_ASSERT(mode == SimRM || mode == SimRZ || mode == SimRN); 3911 3912 bool unsigned_integer = (instr->bit(16) == 0); 3913 bool double_precision = (src_precision == kDoublePrecision); 3914 3915 double val; 3916 if (double_precision) { 3917 get_double_from_d_register(src, &val); 3918 } else { 3919 float fval; 3920 get_float_from_s_register(src, &fval); 3921 val = double(fval); 3922 } 3923 3924 int temp = unsigned_integer ? static_cast<uint32_t>(val) 3925 : static_cast<int32_t>(val); 3926 3927 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer); 3928 3929 double abs_diff = unsigned_integer 3930 ? std::fabs(val - static_cast<uint32_t>(temp)) 3931 : std::fabs(val - temp); 3932 3933 inexact_vfp_flag_ = (abs_diff != 0); 3934 3935 if (inv_op_vfp_flag_) { 3936 temp = VFPConversionSaturate(val, unsigned_integer); 3937 } else { 3938 switch (mode) { 3939 case SimRN: { 3940 int val_sign = (val > 0) ? 1 : -1; 3941 if (abs_diff > 0.5) { 3942 temp += val_sign; 3943 } else if (abs_diff == 0.5) { 3944 // Round to even if exactly halfway. 3945 temp = ((temp % 2) == 0) ? temp : temp + val_sign; 3946 } 3947 break; 3948 } 3949 3950 case SimRM: 3951 temp = temp > val ? temp - 1 : temp; 3952 break; 3953 3954 case SimRZ: 3955 // Nothing to do. 3956 break; 3957 3958 default: 3959 MOZ_CRASH(); 3960 } 3961 } 3962 3963 // Update the destination register. 3964 set_s_register_from_sinteger(dst, temp); 3965 } else { 3966 bool unsigned_integer = (instr->bit(7) == 0); 3967 int dst = instr->VFPDRegValue(src_precision); 3968 int src = instr->VFPMRegValue(kSinglePrecision); 3969 3970 int val = get_sinteger_from_s_register(src); 3971 3972 if (src_precision == kDoublePrecision) { 3973 if (unsigned_integer) { 3974 set_d_register_from_double( 3975 dst, static_cast<double>(static_cast<uint32_t>(val))); 3976 } else { 3977 set_d_register_from_double(dst, static_cast<double>(val)); 3978 } 3979 } else { 3980 if (unsigned_integer) { 3981 set_s_register_from_float( 3982 dst, static_cast<float>(static_cast<uint32_t>(val))); 3983 } else { 3984 set_s_register_from_float(dst, static_cast<float>(val)); 3985 } 3986 } 3987 } 3988 } 3989 3990 // A VFPv3 specific instruction. 3991 void Simulator::decodeVCVTBetweenFloatingPointAndIntegerFrac( 3992 SimInstruction* instr) { 3993 MOZ_ASSERT(instr->bits(27, 24) == 0xE && instr->opc1Value() == 0x7 && 3994 instr->bit(19) == 1 && instr->bit(17) == 1 && 3995 instr->bits(11, 9) == 0x5 && instr->bit(6) == 1 && 3996 instr->bit(4) == 0); 3997 3998 int size = (instr->bit(7) == 1) ? 32 : 16; 3999 4000 int fraction_bits = size - ((instr->bits(3, 0) << 1) | instr->bit(5)); 4001 double mult = 1 << fraction_bits; 4002 4003 MOZ_ASSERT(size == 32); // Only handling size == 32 for now. 4004 4005 // Conversion between floating-point and integer. 4006 bool to_fixed = (instr->bit(18) == 1); 4007 4008 VFPRegPrecision precision = 4009 (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision; 4010 4011 if (to_fixed) { 4012 // We are playing with code close to the C++ standard's limits below, 4013 // hence the very simple code and heavy checks. 4014 // 4015 // Note: C++ defines default type casting from floating point to integer 4016 // as (close to) rounding toward zero ("fractional part discarded"). 4017 4018 int dst = instr->VFPDRegValue(precision); 4019 4020 bool unsigned_integer = (instr->bit(16) == 1); 4021 bool double_precision = (precision == kDoublePrecision); 4022 4023 double val; 4024 if (double_precision) { 4025 get_double_from_d_register(dst, &val); 4026 } else { 4027 float fval; 4028 get_float_from_s_register(dst, &fval); 4029 val = double(fval); 4030 } 4031 4032 // Scale value by specified number of fraction bits. 4033 val *= mult; 4034 4035 // Rounding down towards zero. No need to account for the rounding error 4036 // as this instruction always rounds down towards zero. See SimRZ below. 4037 int temp = unsigned_integer ? static_cast<uint32_t>(val) 4038 : static_cast<int32_t>(val); 4039 4040 inv_op_vfp_flag_ = get_inv_op_vfp_flag(SimRZ, val, unsigned_integer); 4041 4042 double abs_diff = unsigned_integer 4043 ? std::fabs(val - static_cast<uint32_t>(temp)) 4044 : std::fabs(val - temp); 4045 4046 inexact_vfp_flag_ = (abs_diff != 0); 4047 4048 if (inv_op_vfp_flag_) { 4049 temp = VFPConversionSaturate(val, unsigned_integer); 4050 } 4051 4052 // Update the destination register. 4053 if (double_precision) { 4054 uint32_t dbl[2]; 4055 dbl[0] = temp; 4056 dbl[1] = 0; 4057 set_d_register(dst, dbl); 4058 } else { 4059 set_s_register_from_sinteger(dst, temp); 4060 } 4061 } else { 4062 MOZ_CRASH(); // Not implemented, fixed to float. 4063 } 4064 } 4065 4066 void Simulator::decodeVCVTBetweenFloatingPointAndHalf(SimInstruction* instr) { 4067 MOZ_ASSERT(instr->bit(4) == 0 && instr->opc1Value() == 0x7); 4068 MOZ_ASSERT((instr->opc2Value() & ~0x1) == 0x2 && (instr->opc3Value() & 0x1)); 4069 4070 bool top_half = (instr->bit(7) == 1); 4071 bool to_half = (instr->bit(16) == 1); 4072 4073 VFPRegPrecision dst_precision = kSinglePrecision; 4074 VFPRegPrecision src_precision = kSinglePrecision; 4075 if (instr->szValue() == 1) { 4076 if (to_half) { 4077 src_precision = kDoublePrecision; 4078 } else { 4079 dst_precision = kDoublePrecision; 4080 } 4081 } 4082 4083 int dst = instr->VFPDRegValue(dst_precision); 4084 int src = instr->VFPMRegValue(src_precision); 4085 4086 if (to_half) { 4087 uint32_t f16bits; 4088 if (src_precision == kSinglePrecision) { 4089 float val; 4090 get_float_from_s_register(src, &val); 4091 f16bits = js::float16{val}.toRawBits(); 4092 } else { 4093 double val; 4094 get_double_from_d_register(src, &val); 4095 f16bits = js::float16{val}.toRawBits(); 4096 } 4097 4098 float val; 4099 get_float_from_s_register(dst, &val); 4100 uint32_t f32bits = mozilla::BitwiseCast<uint32_t>(val); 4101 4102 if (top_half) { 4103 f32bits = (f16bits << 16) | (f32bits & 0xffff); 4104 } else { 4105 f32bits = (f32bits & 0xffff'0000) | f16bits; 4106 } 4107 4108 float rval; 4109 mozilla::BitwiseCast(f32bits, &rval); 4110 4111 set_s_register_from_float(dst, rval); 4112 } else { 4113 float val; 4114 get_float_from_s_register(src, &val); 4115 uint32_t f32bits = mozilla::BitwiseCast<uint32_t>(val); 4116 4117 if (top_half) { 4118 f32bits >>= 16; 4119 } 4120 4121 auto rval = js::float16::fromRawBits(uint16_t(f32bits)); 4122 4123 if (dst_precision == kSinglePrecision) { 4124 set_s_register_from_float(dst, static_cast<float>(rval)); 4125 } else { 4126 set_d_register_from_double(dst, static_cast<double>(rval)); 4127 } 4128 } 4129 } 4130 4131 void Simulator::decodeType6CoprocessorIns(SimInstruction* instr) { 4132 MOZ_ASSERT(instr->typeValue() == 6); 4133 4134 if (instr->coprocessorValue() == 0xA) { 4135 switch (instr->opcodeValue()) { 4136 case 0x8: 4137 case 0xA: 4138 case 0xC: 4139 case 0xE: { // Load and store single precision float to memory. 4140 int rn = instr->rnValue(); 4141 int vd = instr->VFPDRegValue(kSinglePrecision); 4142 int offset = instr->immed8Value(); 4143 if (!instr->hasU()) { 4144 offset = -offset; 4145 } 4146 4147 int32_t address = get_register(rn) + 4 * offset; 4148 if (instr->hasL()) { 4149 // Load double from memory: vldr. 4150 set_s_register_from_sinteger(vd, readW(address, instr)); 4151 } else { 4152 // Store double to memory: vstr. 4153 writeW(address, get_sinteger_from_s_register(vd), instr); 4154 } 4155 break; 4156 } 4157 case 0x4: 4158 case 0x5: 4159 case 0x6: 4160 case 0x7: 4161 case 0x9: 4162 case 0xB: 4163 // Load/store multiple single from memory: vldm/vstm. 4164 handleVList(instr); 4165 break; 4166 default: 4167 MOZ_CRASH(); 4168 } 4169 } else if (instr->coprocessorValue() == 0xB) { 4170 switch (instr->opcodeValue()) { 4171 case 0x2: 4172 // Load and store double to two GP registers 4173 if (instr->bits(7, 6) != 0 || instr->bit(4) != 1) { 4174 MOZ_CRASH(); // Not used atm. 4175 } else { 4176 int rt = instr->rtValue(); 4177 int rn = instr->rnValue(); 4178 int vm = instr->VFPMRegValue(kDoublePrecision); 4179 if (instr->hasL()) { 4180 int32_t data[2]; 4181 double d; 4182 get_double_from_d_register(vm, &d); 4183 memcpy(data, &d, 8); 4184 set_register(rt, data[0]); 4185 set_register(rn, data[1]); 4186 } else { 4187 int32_t data[] = {get_register(rt), get_register(rn)}; 4188 double d; 4189 memcpy(&d, data, 8); 4190 set_d_register_from_double(vm, d); 4191 } 4192 } 4193 break; 4194 case 0x8: 4195 case 0xA: 4196 case 0xC: 4197 case 0xE: { // Load and store double to memory. 4198 int rn = instr->rnValue(); 4199 int vd = instr->VFPDRegValue(kDoublePrecision); 4200 int offset = instr->immed8Value(); 4201 if (!instr->hasU()) { 4202 offset = -offset; 4203 } 4204 int32_t address = get_register(rn) + 4 * offset; 4205 if (instr->hasL()) { 4206 // Load double from memory: vldr. 4207 uint64_t data = readQ(address, instr); 4208 double val; 4209 memcpy(&val, &data, 8); 4210 set_d_register_from_double(vd, val); 4211 } else { 4212 // Store double to memory: vstr. 4213 uint64_t data; 4214 double val; 4215 get_double_from_d_register(vd, &val); 4216 memcpy(&data, &val, 8); 4217 writeQ(address, data, instr); 4218 } 4219 break; 4220 } 4221 case 0x4: 4222 case 0x5: 4223 case 0x6: 4224 case 0x7: 4225 case 0x9: 4226 case 0xB: 4227 // Load/store multiple double from memory: vldm/vstm. 4228 handleVList(instr); 4229 break; 4230 default: 4231 MOZ_CRASH(); 4232 } 4233 } else { 4234 MOZ_CRASH(); 4235 } 4236 } 4237 4238 void Simulator::decodeSpecialCondition(SimInstruction* instr) { 4239 switch (instr->specialValue()) { 4240 case 5: 4241 if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 && 4242 instr->bit(4) == 1) { 4243 // vmovl signed 4244 if ((instr->vdValue() & 1) != 0) { 4245 MOZ_CRASH("Undefined behavior"); 4246 } 4247 int Vd = (instr->bit(22) << 3) | (instr->vdValue() >> 1); 4248 int Vm = (instr->bit(5) << 4) | instr->vmValue(); 4249 int imm3 = instr->bits(21, 19); 4250 if (imm3 != 1 && imm3 != 2 && imm3 != 4) { 4251 MOZ_CRASH(); 4252 } 4253 int esize = 8 * imm3; 4254 int elements = 64 / esize; 4255 int8_t from[8]; 4256 get_d_register(Vm, reinterpret_cast<uint64_t*>(from)); 4257 int16_t to[8]; 4258 int e = 0; 4259 while (e < elements) { 4260 to[e] = from[e]; 4261 e++; 4262 } 4263 set_q_register(Vd, reinterpret_cast<uint64_t*>(to)); 4264 } else { 4265 MOZ_CRASH(); 4266 } 4267 break; 4268 case 7: 4269 if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 && 4270 instr->bit(4) == 1) { 4271 // vmovl unsigned. 4272 if ((instr->vdValue() & 1) != 0) { 4273 MOZ_CRASH("Undefined behavior"); 4274 } 4275 int Vd = (instr->bit(22) << 3) | (instr->vdValue() >> 1); 4276 int Vm = (instr->bit(5) << 4) | instr->vmValue(); 4277 int imm3 = instr->bits(21, 19); 4278 if (imm3 != 1 && imm3 != 2 && imm3 != 4) { 4279 MOZ_CRASH(); 4280 } 4281 int esize = 8 * imm3; 4282 int elements = 64 / esize; 4283 uint8_t from[8]; 4284 get_d_register(Vm, reinterpret_cast<uint64_t*>(from)); 4285 uint16_t to[8]; 4286 int e = 0; 4287 while (e < elements) { 4288 to[e] = from[e]; 4289 e++; 4290 } 4291 set_q_register(Vd, reinterpret_cast<uint64_t*>(to)); 4292 } else { 4293 MOZ_CRASH(); 4294 } 4295 break; 4296 case 8: 4297 if (instr->bits(21, 20) == 0) { 4298 // vst1 4299 int Vd = (instr->bit(22) << 4) | instr->vdValue(); 4300 int Rn = instr->vnValue(); 4301 int type = instr->bits(11, 8); 4302 int Rm = instr->vmValue(); 4303 int32_t address = get_register(Rn); 4304 int regs = 0; 4305 switch (type) { 4306 case nlt_1: 4307 regs = 1; 4308 break; 4309 case nlt_2: 4310 regs = 2; 4311 break; 4312 case nlt_3: 4313 regs = 3; 4314 break; 4315 case nlt_4: 4316 regs = 4; 4317 break; 4318 default: 4319 MOZ_CRASH(); 4320 break; 4321 } 4322 int r = 0; 4323 while (r < regs) { 4324 uint32_t data[2]; 4325 get_d_register(Vd + r, data); 4326 // TODO: We should AllowUnaligned here only if the alignment attribute 4327 // of the instruction calls for default alignment. 4328 // 4329 // Use writeQ to get handling of traps right. (The spec says to 4330 // perform two individual word writes, but let's not worry about 4331 // that.) 4332 writeQ(address, (uint64_t(data[1]) << 32) | uint64_t(data[0]), instr, 4333 AllowUnaligned); 4334 address += 8; 4335 r++; 4336 } 4337 if (Rm != 15) { 4338 if (Rm == 13) { 4339 set_register(Rn, address); 4340 } else { 4341 set_register(Rn, get_register(Rn) + get_register(Rm)); 4342 } 4343 } 4344 } else if (instr->bits(21, 20) == 2) { 4345 // vld1 4346 int Vd = (instr->bit(22) << 4) | instr->vdValue(); 4347 int Rn = instr->vnValue(); 4348 int type = instr->bits(11, 8); 4349 int Rm = instr->vmValue(); 4350 int32_t address = get_register(Rn); 4351 int regs = 0; 4352 switch (type) { 4353 case nlt_1: 4354 regs = 1; 4355 break; 4356 case nlt_2: 4357 regs = 2; 4358 break; 4359 case nlt_3: 4360 regs = 3; 4361 break; 4362 case nlt_4: 4363 regs = 4; 4364 break; 4365 default: 4366 MOZ_CRASH(); 4367 break; 4368 } 4369 int r = 0; 4370 while (r < regs) { 4371 uint32_t data[2]; 4372 // TODO: We should AllowUnaligned here only if the alignment attribute 4373 // of the instruction calls for default alignment. 4374 // 4375 // Use readQ to get handling of traps right. (The spec says to 4376 // perform two individual word reads, but let's not worry about that.) 4377 uint64_t tmp = readQ(address, instr, AllowUnaligned); 4378 data[0] = tmp; 4379 data[1] = tmp >> 32; 4380 set_d_register(Vd + r, data); 4381 address += 8; 4382 r++; 4383 } 4384 if (Rm != 15) { 4385 if (Rm == 13) { 4386 set_register(Rn, address); 4387 } else { 4388 set_register(Rn, get_register(Rn) + get_register(Rm)); 4389 } 4390 } 4391 } else { 4392 MOZ_CRASH(); 4393 } 4394 break; 4395 case 9: 4396 if (instr->bits(9, 8) == 0) { 4397 int Vd = (instr->bit(22) << 4) | instr->vdValue(); 4398 int Rn = instr->vnValue(); 4399 int size = instr->bits(11, 10); 4400 int Rm = instr->vmValue(); 4401 int index = instr->bits(7, 5); 4402 int align = instr->bit(4); 4403 int32_t address = get_register(Rn); 4404 if (size != 2 || align) { 4405 MOZ_CRASH("NYI"); 4406 } 4407 int a = instr->bits(5, 4); 4408 if (a != 0 && a != 3) { 4409 MOZ_CRASH("Unspecified"); 4410 } 4411 if (index > 1) { 4412 Vd++; 4413 index -= 2; 4414 } 4415 uint32_t data[2]; 4416 get_d_register(Vd, data); 4417 switch (instr->bits(21, 20)) { 4418 case 0: 4419 // vst1 single element from one lane 4420 writeW(address, data[index], instr, AllowUnaligned); 4421 break; 4422 case 2: 4423 // vld1 single element to one lane 4424 data[index] = readW(address, instr, AllowUnaligned); 4425 set_d_register(Vd, data); 4426 break; 4427 default: 4428 MOZ_CRASH("NYI"); 4429 } 4430 address += 4; 4431 if (Rm != 15) { 4432 if (Rm == 13) { 4433 set_register(Rn, address); 4434 } else { 4435 set_register(Rn, get_register(Rn) + get_register(Rm)); 4436 } 4437 } 4438 } else { 4439 MOZ_CRASH(); 4440 } 4441 break; 4442 case 0xA: 4443 if (instr->bits(31, 20) == 0xf57) { 4444 switch (instr->bits(7, 4)) { 4445 case 1: // CLREX 4446 exclusiveMonitorClear(); 4447 break; 4448 case 5: // DMB 4449 AtomicOperations::fenceSeqCst(); 4450 break; 4451 case 4: // DSB 4452 // We do not use DSB. 4453 MOZ_CRASH("DSB unimplemented"); 4454 case 6: // ISB 4455 // We do not use ISB. 4456 MOZ_CRASH("ISB unimplemented"); 4457 default: 4458 MOZ_CRASH(); 4459 } 4460 } else { 4461 MOZ_CRASH(); 4462 } 4463 break; 4464 case 0xB: 4465 if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) { 4466 // pld: ignore instruction. 4467 } else { 4468 MOZ_CRASH(); 4469 } 4470 break; 4471 case 0x1C: 4472 case 0x1D: 4473 if (instr->bit(4) == 1 && instr->bits(11, 9) != 5) { 4474 // MCR, MCR2, MRC, MRC2 with cond == 15 4475 decodeType7CoprocessorIns(instr); 4476 } else { 4477 MOZ_CRASH(); 4478 } 4479 break; 4480 default: 4481 MOZ_CRASH(); 4482 } 4483 } 4484 4485 // Executes the current instruction. 4486 void Simulator::instructionDecode(SimInstruction* instr) { 4487 if (!SimulatorProcess::ICacheCheckingDisableCount) { 4488 AutoLockSimulatorCache als; 4489 SimulatorProcess::checkICacheLocked(instr); 4490 } 4491 4492 pc_modified_ = false; 4493 4494 static const uint32_t kSpecialCondition = 15 << 28; 4495 if (instr->conditionField() == kSpecialCondition) { 4496 decodeSpecialCondition(instr); 4497 } else if (conditionallyExecute(instr)) { 4498 switch (instr->typeValue()) { 4499 case 0: 4500 case 1: 4501 decodeType01(instr); 4502 break; 4503 case 2: 4504 decodeType2(instr); 4505 break; 4506 case 3: 4507 decodeType3(instr); 4508 break; 4509 case 4: 4510 decodeType4(instr); 4511 break; 4512 case 5: 4513 decodeType5(instr); 4514 break; 4515 case 6: 4516 decodeType6(instr); 4517 break; 4518 case 7: 4519 decodeType7(instr); 4520 break; 4521 default: 4522 MOZ_CRASH(); 4523 break; 4524 } 4525 // If the instruction is a non taken conditional stop, we need to skip 4526 // the inlined message address. 4527 } else if (instr->isStop()) { 4528 set_pc(get_pc() + 2 * SimInstruction::kInstrSize); 4529 } 4530 if (!pc_modified_) { 4531 set_register(pc, 4532 reinterpret_cast<int32_t>(instr) + SimInstruction::kInstrSize); 4533 } 4534 } 4535 4536 void Simulator::enable_single_stepping(SingleStepCallback cb, void* arg) { 4537 single_stepping_ = true; 4538 single_step_callback_ = cb; 4539 single_step_callback_arg_ = arg; 4540 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc()); 4541 } 4542 4543 void Simulator::disable_single_stepping() { 4544 if (!single_stepping_) { 4545 return; 4546 } 4547 single_step_callback_(single_step_callback_arg_, this, (void*)get_pc()); 4548 single_stepping_ = false; 4549 single_step_callback_ = nullptr; 4550 single_step_callback_arg_ = nullptr; 4551 } 4552 4553 template <bool EnableStopSimAt> 4554 void Simulator::execute() { 4555 if (single_stepping_) { 4556 single_step_callback_(single_step_callback_arg_, this, nullptr); 4557 } 4558 4559 // Get the PC to simulate. Cannot use the accessor here as we need the raw 4560 // PC value and not the one used as input to arithmetic instructions. 4561 int program_counter = get_pc(); 4562 4563 while (program_counter != end_sim_pc) { 4564 if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) { 4565 fprintf(stderr, "\nStopped simulation at icount %lld\n", icount_); 4566 ArmDebugger dbg(this); 4567 dbg.debug(); 4568 } else { 4569 if (single_stepping_) { 4570 single_step_callback_(single_step_callback_arg_, this, 4571 (void*)program_counter); 4572 } 4573 SimInstruction* instr = 4574 reinterpret_cast<SimInstruction*>(program_counter); 4575 instructionDecode(instr); 4576 icount_++; 4577 } 4578 program_counter = get_pc(); 4579 } 4580 4581 if (single_stepping_) { 4582 single_step_callback_(single_step_callback_arg_, this, nullptr); 4583 } 4584 } 4585 4586 void Simulator::callInternal(uint8_t* entry) { 4587 // Prepare to execute the code at entry. 4588 set_register(pc, reinterpret_cast<int32_t>(entry)); 4589 4590 // Put down marker for end of simulation. The simulator will stop simulation 4591 // when the PC reaches this value. By saving the "end simulation" value into 4592 // the LR the simulation stops when returning to this call point. 4593 set_register(lr, end_sim_pc); 4594 4595 // Remember the values of callee-saved registers. The code below assumes 4596 // that r9 is not used as sb (static base) in simulator code and therefore 4597 // is regarded as a callee-saved register. 4598 int32_t r4_val = get_register(r4); 4599 int32_t r5_val = get_register(r5); 4600 int32_t r6_val = get_register(r6); 4601 int32_t r7_val = get_register(r7); 4602 int32_t r8_val = get_register(r8); 4603 int32_t r9_val = get_register(r9); 4604 int32_t r10_val = get_register(r10); 4605 int32_t r11_val = get_register(r11); 4606 4607 // Remember d8 to d15 which are callee-saved. 4608 uint64_t d8_val; 4609 get_d_register(d8, &d8_val); 4610 uint64_t d9_val; 4611 get_d_register(d9, &d9_val); 4612 uint64_t d10_val; 4613 get_d_register(d10, &d10_val); 4614 uint64_t d11_val; 4615 get_d_register(d11, &d11_val); 4616 uint64_t d12_val; 4617 get_d_register(d12, &d12_val); 4618 uint64_t d13_val; 4619 get_d_register(d13, &d13_val); 4620 uint64_t d14_val; 4621 get_d_register(d14, &d14_val); 4622 uint64_t d15_val; 4623 get_d_register(d15, &d15_val); 4624 4625 // Set up the callee-saved registers with a known value. To be able to check 4626 // that they are preserved properly across JS execution. 4627 int32_t callee_saved_value = uint32_t(icount_); 4628 uint64_t callee_saved_value_d = uint64_t(icount_); 4629 4630 if (!skipCalleeSavedRegsCheck) { 4631 set_register(r4, callee_saved_value); 4632 set_register(r5, callee_saved_value); 4633 set_register(r6, callee_saved_value); 4634 set_register(r7, callee_saved_value); 4635 set_register(r8, callee_saved_value); 4636 set_register(r9, callee_saved_value); 4637 set_register(r10, callee_saved_value); 4638 set_register(r11, callee_saved_value); 4639 4640 set_d_register(d8, &callee_saved_value_d); 4641 set_d_register(d9, &callee_saved_value_d); 4642 set_d_register(d10, &callee_saved_value_d); 4643 set_d_register(d11, &callee_saved_value_d); 4644 set_d_register(d12, &callee_saved_value_d); 4645 set_d_register(d13, &callee_saved_value_d); 4646 set_d_register(d14, &callee_saved_value_d); 4647 set_d_register(d15, &callee_saved_value_d); 4648 } 4649 // Start the simulation. 4650 if (Simulator::StopSimAt != -1L) { 4651 execute<true>(); 4652 } else { 4653 execute<false>(); 4654 } 4655 4656 if (!skipCalleeSavedRegsCheck) { 4657 // Check that the callee-saved registers have been preserved. 4658 MOZ_ASSERT(callee_saved_value == get_register(r4)); 4659 MOZ_ASSERT(callee_saved_value == get_register(r5)); 4660 MOZ_ASSERT(callee_saved_value == get_register(r6)); 4661 MOZ_ASSERT(callee_saved_value == get_register(r7)); 4662 MOZ_ASSERT(callee_saved_value == get_register(r8)); 4663 MOZ_ASSERT(callee_saved_value == get_register(r9)); 4664 MOZ_ASSERT(callee_saved_value == get_register(r10)); 4665 MOZ_ASSERT(callee_saved_value == get_register(r11)); 4666 4667 uint64_t value; 4668 get_d_register(d8, &value); 4669 MOZ_ASSERT(callee_saved_value_d == value); 4670 get_d_register(d9, &value); 4671 MOZ_ASSERT(callee_saved_value_d == value); 4672 get_d_register(d10, &value); 4673 MOZ_ASSERT(callee_saved_value_d == value); 4674 get_d_register(d11, &value); 4675 MOZ_ASSERT(callee_saved_value_d == value); 4676 get_d_register(d12, &value); 4677 MOZ_ASSERT(callee_saved_value_d == value); 4678 get_d_register(d13, &value); 4679 MOZ_ASSERT(callee_saved_value_d == value); 4680 get_d_register(d14, &value); 4681 MOZ_ASSERT(callee_saved_value_d == value); 4682 get_d_register(d15, &value); 4683 MOZ_ASSERT(callee_saved_value_d == value); 4684 4685 // Restore callee-saved registers with the original value. 4686 set_register(r4, r4_val); 4687 set_register(r5, r5_val); 4688 set_register(r6, r6_val); 4689 set_register(r7, r7_val); 4690 set_register(r8, r8_val); 4691 set_register(r9, r9_val); 4692 set_register(r10, r10_val); 4693 set_register(r11, r11_val); 4694 4695 set_d_register(d8, &d8_val); 4696 set_d_register(d9, &d9_val); 4697 set_d_register(d10, &d10_val); 4698 set_d_register(d11, &d11_val); 4699 set_d_register(d12, &d12_val); 4700 set_d_register(d13, &d13_val); 4701 set_d_register(d14, &d14_val); 4702 set_d_register(d15, &d15_val); 4703 } 4704 } 4705 4706 int32_t Simulator::call(uint8_t* entry, int argument_count, ...) { 4707 va_list parameters; 4708 va_start(parameters, argument_count); 4709 4710 // First four arguments passed in registers. 4711 if (argument_count >= 1) { 4712 set_register(r0, va_arg(parameters, int32_t)); 4713 } 4714 if (argument_count >= 2) { 4715 set_register(r1, va_arg(parameters, int32_t)); 4716 } 4717 if (argument_count >= 3) { 4718 set_register(r2, va_arg(parameters, int32_t)); 4719 } 4720 if (argument_count >= 4) { 4721 set_register(r3, va_arg(parameters, int32_t)); 4722 } 4723 4724 // Remaining arguments passed on stack. 4725 int original_stack = get_register(sp); 4726 int entry_stack = original_stack; 4727 if (argument_count >= 4) { 4728 entry_stack -= (argument_count - 4) * sizeof(int32_t); 4729 } 4730 4731 entry_stack &= ~ABIStackAlignment; 4732 4733 // Store remaining arguments on stack, from low to high memory. 4734 intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack); 4735 for (int i = 4; i < argument_count; i++) { 4736 stack_argument[i - 4] = va_arg(parameters, int32_t); 4737 } 4738 va_end(parameters); 4739 set_register(sp, entry_stack); 4740 4741 callInternal(entry); 4742 4743 // Pop stack passed arguments. 4744 MOZ_ASSERT(entry_stack == get_register(sp)); 4745 set_register(sp, original_stack); 4746 4747 int32_t result = get_register(r0); 4748 return result; 4749 } 4750 4751 Simulator* Simulator::Current() { 4752 JSContext* cx = TlsContext.get(); 4753 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); 4754 return cx->simulator(); 4755 } 4756 4757 } // namespace jit 4758 } // namespace js 4759 4760 js::jit::Simulator* JSContext::simulator() const { return simulator_; }