Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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.
29 #include "jit/arm/Simulator-arm.h"
31 #include "mozilla/Casting.h"
32 #include "mozilla/FloatingPoint.h"
33 #include "mozilla/Likely.h"
34 #include "mozilla/MathAlgorithms.h"
36 #include "jit/arm/Assembler-arm.h"
37 #include "jit/AsmJS.h"
38 #include "vm/Runtime.h"
40 extern "C" {
42 int64_t
43 __aeabi_idivmod(int x, int y)
44 {
45 uint32_t lo = uint32_t(x / y);
46 uint32_t hi = uint32_t(x % y);
47 return (int64_t(hi) << 32) | lo;
48 }
50 int64_t
51 __aeabi_uidivmod(int x, int y)
52 {
53 uint32_t lo = uint32_t(x) / uint32_t(y);
54 uint32_t hi = uint32_t(x) % uint32_t(y);
55 return (int64_t(hi) << 32) | lo;
56 }
57 }
59 namespace js {
60 namespace jit {
62 // Load/store multiple addressing mode.
63 enum BlockAddrMode {
64 // Alias modes for comparison when writeback does not matter.
65 da_x = (0|0|0) << 21, // Decrement after.
66 ia_x = (0|4|0) << 21, // Increment after.
67 db_x = (8|0|0) << 21, // Decrement before.
68 ib_x = (8|4|0) << 21, // Increment before.
69 };
71 // Type of VFP register. Determines register encoding.
72 enum VFPRegPrecision {
73 kSinglePrecision = 0,
74 kDoublePrecision = 1
75 };
77 enum NeonListType {
78 nlt_1 = 0x7,
79 nlt_2 = 0xA,
80 nlt_3 = 0x6,
81 nlt_4 = 0x2
82 };
84 // Supervisor Call (svc) specific support.
86 // Special Software Interrupt codes when used in the presence of the ARM
87 // simulator.
88 // svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for
89 // standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature.
90 enum SoftwareInterruptCodes {
91 kCallRtRedirected = 0x10, // Transition to C code.
92 kBreakpoint= 0x20, // Breakpoint.
93 kStopCode = 1 << 23 // Stop.
94 };
96 const uint32_t kStopCodeMask = kStopCode - 1;
97 const uint32_t kMaxStopCode = kStopCode - 1;
99 // -----------------------------------------------------------------------------
100 // Instruction abstraction.
102 // The class Instruction enables access to individual fields defined in the ARM
103 // architecture instruction set encoding as described in figure A3-1.
104 // Note that the Assembler uses typedef int32_t Instr.
105 //
106 // Example: Test whether the instruction at ptr does set the condition code
107 // bits.
108 //
109 // bool InstructionSetsConditionCodes(byte* ptr) {
110 // Instruction* instr = Instruction::At(ptr);
111 // int type = instr->TypeValue();
112 // return ((type == 0) || (type == 1)) && instr->hasS();
113 // }
114 //
115 class SimInstruction {
116 public:
117 enum {
118 kInstrSize = 4,
119 kPCReadOffset = 8
120 };
122 // Get the raw instruction bits.
123 inline Instr instructionBits() const {
124 return *reinterpret_cast<const Instr*>(this);
125 }
127 // Set the raw instruction bits to value.
128 inline void setInstructionBits(Instr value) {
129 *reinterpret_cast<Instr*>(this) = value;
130 }
132 // Read one particular bit out of the instruction bits.
133 inline int bit(int nr) const {
134 return (instructionBits() >> nr) & 1;
135 }
137 // Read a bit field's value out of the instruction bits.
138 inline int bits(int hi, int lo) const {
139 return (instructionBits() >> lo) & ((2 << (hi - lo)) - 1);
140 }
142 // Read a bit field out of the instruction bits.
143 inline int bitField(int hi, int lo) const {
144 return instructionBits() & (((2 << (hi - lo)) - 1) << lo);
145 }
147 // Accessors for the different named fields used in the ARM encoding.
148 // The naming of these accessor corresponds to figure A3-1.
149 //
150 // Two kind of accessors are declared:
151 // - <Name>Field() will return the raw field, i.e. the field's bits at their
152 // original place in the instruction encoding.
153 // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as
154 // 0xC0810002 conditionField(instr) will return 0xC0000000.
155 // - <Name>Value() will return the field value, shifted back to bit 0.
156 // e.g. if instr is the 'addgt r0, r1, r2' instruction, encoded as
157 // 0xC0810002 conditionField(instr) will return 0xC.
159 // Generally applicable fields
160 inline Assembler::ARMCondition conditionField() const {
161 return static_cast<Assembler::ARMCondition>(bitField(31, 28));
162 }
163 inline int typeValue() const { return bits(27, 25); }
164 inline int specialValue() const { return bits(27, 23); }
166 inline int rnValue() const { return bits(19, 16); }
167 inline int rdValue() const { return bits(15, 12); }
169 inline int coprocessorValue() const { return bits(11, 8); }
171 // Support for VFP.
172 // Vn(19-16) | Vd(15-12) | Vm(3-0)
173 inline int vnValue() const { return bits(19, 16); }
174 inline int vmValue() const { return bits(3, 0); }
175 inline int vdValue() const { return bits(15, 12); }
176 inline int nValue() const { return bit(7); }
177 inline int mValue() const { return bit(5); }
178 inline int dValue() const { return bit(22); }
179 inline int rtValue() const { return bits(15, 12); }
180 inline int pValue() const { return bit(24); }
181 inline int uValue() const { return bit(23); }
182 inline int opc1Value() const { return (bit(23) << 2) | bits(21, 20); }
183 inline int opc2Value() const { return bits(19, 16); }
184 inline int opc3Value() const { return bits(7, 6); }
185 inline int szValue() const { return bit(8); }
186 inline int VLValue() const { return bit(20); }
187 inline int VCValue() const { return bit(8); }
188 inline int VAValue() const { return bits(23, 21); }
189 inline int VBValue() const { return bits(6, 5); }
190 inline int VFPNRegValue(VFPRegPrecision pre) { return VFPGlueRegValue(pre, 16, 7); }
191 inline int VFPMRegValue(VFPRegPrecision pre) { return VFPGlueRegValue(pre, 0, 5); }
192 inline int VFPDRegValue(VFPRegPrecision pre) { return VFPGlueRegValue(pre, 12, 22); }
194 // Fields used in Data processing instructions
195 inline int opcodeValue() const { return static_cast<ALUOp>(bits(24, 21)); }
196 inline ALUOp opcodeField() const { return static_cast<ALUOp>(bitField(24, 21)); }
197 inline int sValue() const { return bit(20); }
199 // with register
200 inline int rmValue() const { return bits(3, 0); }
201 inline ShiftType shifttypeValue() const { return static_cast<ShiftType>(bits(6, 5)); }
202 inline int rsValue() const { return bits(11, 8); }
203 inline int shiftAmountValue() const { return bits(11, 7); }
205 // with immediate
206 inline int rotateValue() const { return bits(11, 8); }
207 inline int immed8Value() const { return bits(7, 0); }
208 inline int immed4Value() const { return bits(19, 16); }
209 inline int immedMovwMovtValue() const { return immed4Value() << 12 | offset12Value(); }
211 // Fields used in Load/Store instructions
212 inline int PUValue() const { return bits(24, 23); }
213 inline int PUField() const { return bitField(24, 23); }
214 inline int bValue() const { return bit(22); }
215 inline int wValue() const { return bit(21); }
216 inline int lValue() const { return bit(20); }
218 // with register uses same fields as Data processing instructions above
219 // with immediate
220 inline int offset12Value() const { return bits(11, 0); }
222 // multiple
223 inline int rlistValue() const { return bits(15, 0); }
225 // extra loads and stores
226 inline int signValue() const { return bit(6); }
227 inline int hValue() const { return bit(5); }
228 inline int immedHValue() const { return bits(11, 8); }
229 inline int immedLValue() const { return bits(3, 0); }
231 // Fields used in Branch instructions
232 inline int linkValue() const { return bit(24); }
233 inline int sImmed24Value() const { return ((instructionBits() << 8) >> 8); }
235 // Fields used in Software interrupt instructions
236 inline SoftwareInterruptCodes svcValue() const {
237 return static_cast<SoftwareInterruptCodes>(bits(23, 0));
238 }
240 // Test for special encodings of type 0 instructions (extra loads and stores,
241 // as well as multiplications).
242 inline bool isSpecialType0() const { return (bit(7) == 1) && (bit(4) == 1); }
244 // Test for miscellaneous instructions encodings of type 0 instructions.
245 inline bool isMiscType0() const {
246 return bit(24) == 1 && bit(23) == 0 && bit(20) == 0 && (bit(7) == 0);
247 }
249 // Test for a nop instruction, which falls under type 1.
250 inline bool isNopType1() const { return bits(24, 0) == 0x0120F000; }
252 // Test for a stop instruction.
253 inline bool isStop() const {
254 return typeValue() == 7 && bit(24) == 1 && svcValue() >= kStopCode;
255 }
257 // Special accessors that test for existence of a value.
258 inline bool hasS() const { return sValue() == 1; }
259 inline bool hasB() const { return bValue() == 1; }
260 inline bool hasW() const { return wValue() == 1; }
261 inline bool hasL() const { return lValue() == 1; }
262 inline bool hasU() const { return uValue() == 1; }
263 inline bool hasSign() const { return signValue() == 1; }
264 inline bool hasH() const { return hValue() == 1; }
265 inline bool hasLink() const { return linkValue() == 1; }
267 // Decoding the double immediate in the vmov instruction.
268 double doubleImmedVmov() const;
269 // Decoding the float32 immediate in the vmov.f32 instruction.
270 float float32ImmedVmov() const;
272 private:
273 // Join split register codes, depending on single or double precision.
274 // four_bit is the position of the least-significant bit of the four
275 // bit specifier. one_bit is the position of the additional single bit
276 // specifier.
277 inline int VFPGlueRegValue(VFPRegPrecision pre, int four_bit, int one_bit) {
278 if (pre == kSinglePrecision)
279 return (bits(four_bit + 3, four_bit) << 1) | bit(one_bit);
280 return (bit(one_bit) << 4) | bits(four_bit + 3, four_bit);
281 }
283 SimInstruction() MOZ_DELETE;
284 SimInstruction(const SimInstruction &other) MOZ_DELETE;
285 void operator=(const SimInstruction &other) MOZ_DELETE;
286 };
288 double
289 SimInstruction::doubleImmedVmov() const
290 {
291 // Reconstruct a double from the immediate encoded in the vmov instruction.
292 //
293 // instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
294 // double: [aBbbbbbb,bbcdefgh,00000000,00000000,
295 // 00000000,00000000,00000000,00000000]
296 //
297 // where B = ~b. Only the high 16 bits are affected.
298 uint64_t high16;
299 high16 = (bits(17, 16) << 4) | bits(3, 0); // xxxxxxxx,xxcdefgh.
300 high16 |= (0xff * bit(18)) << 6; // xxbbbbbb,bbxxxxxx.
301 high16 |= (bit(18) ^ 1) << 14; // xBxxxxxx,xxxxxxxx.
302 high16 |= bit(19) << 15; // axxxxxxx,xxxxxxxx.
304 uint64_t imm = high16 << 48;
305 return mozilla::BitwiseCast<double>(imm);
306 }
308 float
309 SimInstruction::float32ImmedVmov() const
310 {
311 // Reconstruct a float32 from the immediate encoded in the vmov instruction.
312 //
313 // instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
314 // float32: [aBbbbbbc, defgh000, 00000000, 00000000]
315 //
316 // where B = ~b. Only the high 16 bits are affected.
317 uint32_t imm;
318 imm = (bits(17, 16) << 23) | (bits(3, 0) << 19); // xxxxxxxc,defgh000.0.0
319 imm |= (0x1f * bit(18)) << 25; // xxbbbbbx,xxxxxxxx.0.0
320 imm |= (bit(18) ^ 1) << 30; // xBxxxxxx,xxxxxxxx.0.0
321 imm |= bit(19) << 31; // axxxxxxx,xxxxxxxx.0.0
323 return mozilla::BitwiseCast<float>(imm);
324 }
326 class CachePage
327 {
328 public:
329 static const int LINE_VALID = 0;
330 static const int LINE_INVALID = 1;
331 static const int kPageShift = 12;
332 static const int kPageSize = 1 << kPageShift;
333 static const int kPageMask = kPageSize - 1;
334 static const int kLineShift = 2; // The cache line is only 4 bytes right now.
335 static const int kLineLength = 1 << kLineShift;
336 static const int kLineMask = kLineLength - 1;
338 CachePage() {
339 memset(&validity_map_, LINE_INVALID, sizeof(validity_map_));
340 }
341 char *validityByte(int offset) {
342 return &validity_map_[offset >> kLineShift];
343 }
344 char *cachedData(int offset) {
345 return &data_[offset];
346 }
348 private:
349 char data_[kPageSize]; // The cached data.
350 static const int kValidityMapSize = kPageSize >> kLineShift;
351 char validity_map_[kValidityMapSize]; // One byte per line.
352 };
354 class Redirection;
356 class SimulatorRuntime
357 {
358 friend class AutoLockSimulatorRuntime;
360 Redirection *redirection_;
362 // ICache checking.
363 struct ICacheHasher {
364 typedef void *Key;
365 typedef void *Lookup;
366 static HashNumber hash(const Lookup &l);
367 static bool match(const Key &k, const Lookup &l);
368 };
370 public:
371 typedef HashMap<void *, CachePage *, ICacheHasher, SystemAllocPolicy> ICacheMap;
373 protected:
374 ICacheMap icache_;
376 // Synchronize access between main thread and compilation/PJS threads.
377 PRLock *lock_;
378 mozilla::DebugOnly<PRThread *> lockOwner_;
380 public:
381 SimulatorRuntime()
382 : redirection_(nullptr),
383 lock_(nullptr),
384 lockOwner_(nullptr)
385 {}
386 ~SimulatorRuntime();
387 bool init() {
388 #ifdef JS_THREADSAFE
389 lock_ = PR_NewLock();
390 if (!lock_)
391 return false;
392 #endif
393 if (!icache_.init())
394 return false;
395 return true;
396 }
397 ICacheMap &icache() {
398 #ifdef JS_THREADSAFE
399 MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
400 #endif
401 return icache_;
402 }
403 Redirection *redirection() const {
404 #ifdef JS_THREADSAFE
405 MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
406 #endif
407 return redirection_;
408 }
409 void setRedirection(js::jit::Redirection *redirection) {
410 #ifdef JS_THREADSAFE
411 MOZ_ASSERT(lockOwner_ == PR_GetCurrentThread());
412 #endif
413 redirection_ = redirection;
414 }
415 };
417 class AutoLockSimulatorRuntime
418 {
419 protected:
420 SimulatorRuntime *srt_;
422 public:
423 AutoLockSimulatorRuntime(SimulatorRuntime *srt)
424 : srt_(srt)
425 {
426 #ifdef JS_THREADSAFE
427 PR_Lock(srt_->lock_);
428 MOZ_ASSERT(!srt_->lockOwner_);
429 #ifdef DEBUG
430 srt_->lockOwner_ = PR_GetCurrentThread();
431 #endif
432 #endif
433 }
435 ~AutoLockSimulatorRuntime() {
436 #ifdef JS_THREADSAFE
437 MOZ_ASSERT(srt_->lockOwner_ == PR_GetCurrentThread());
438 srt_->lockOwner_ = nullptr;
439 PR_Unlock(srt_->lock_);
440 #endif
441 }
442 };
444 bool Simulator::ICacheCheckingEnabled = false;
446 int64_t Simulator::StopSimAt = -1L;
448 SimulatorRuntime *
449 CreateSimulatorRuntime()
450 {
451 SimulatorRuntime *srt = js_new<SimulatorRuntime>();
452 if (!srt)
453 return nullptr;
455 if (!srt->init()) {
456 js_delete(srt);
457 return nullptr;
458 }
460 if (getenv("ARM_SIM_ICACHE_CHECKS"))
461 Simulator::ICacheCheckingEnabled = true;
463 char *stopAtStr = getenv("ARM_SIM_STOP_AT");
464 int64_t stopAt;
465 if (stopAtStr && sscanf(stopAtStr, "%lld", &stopAt) == 1) {
466 fprintf(stderr, "\nStopping simulation at icount %lld\n", stopAt);
467 Simulator::StopSimAt = stopAt;
468 }
470 return srt;
471 }
473 void
474 DestroySimulatorRuntime(SimulatorRuntime *srt)
475 {
476 js_delete(srt);
477 }
479 // The ArmDebugger class is used by the simulator while debugging simulated ARM
480 // code.
481 class ArmDebugger {
482 public:
483 explicit ArmDebugger(Simulator *sim) : sim_(sim) { }
485 void stop(SimInstruction *instr);
486 void debug();
488 private:
489 static const Instr kBreakpointInstr = (Assembler::AL | (7 * (1 << 25)) | (1* (1 << 24)) | kBreakpoint);
490 static const Instr kNopInstr = (Assembler::AL | (13 * (1 << 21)));
492 Simulator* sim_;
494 int32_t getRegisterValue(int regnum);
495 double getRegisterPairDoubleValue(int regnum);
496 double getVFPDoubleRegisterValue(int regnum);
497 bool getValue(const char *desc, int32_t *value);
498 bool getVFPDoubleValue(const char *desc, double *value);
500 // Set or delete a breakpoint. Returns true if successful.
501 bool setBreakpoint(SimInstruction *breakpc);
502 bool deleteBreakpoint(SimInstruction *breakpc);
504 // Undo and redo all breakpoints. This is needed to bracket disassembly and
505 // execution to skip past breakpoints when run from the debugger.
506 void undoBreakpoints();
507 void redoBreakpoints();
508 };
510 void
511 ArmDebugger::stop(SimInstruction * instr)
512 {
513 // Get the stop code.
514 uint32_t code = instr->svcValue() & kStopCodeMask;
515 // Retrieve the encoded address, which comes just after this stop.
516 char* msg = *reinterpret_cast<char**>(sim_->get_pc()
517 + SimInstruction::kInstrSize);
518 // Update this stop description.
519 if (sim_->isWatchedStop(code) && !sim_->watched_stops_[code].desc) {
520 sim_->watched_stops_[code].desc = msg;
521 }
522 // Print the stop message and code if it is not the default code.
523 if (code != kMaxStopCode) {
524 printf("Simulator hit stop %u: %s\n", code, msg);
525 } else {
526 printf("Simulator hit %s\n", msg);
527 }
528 sim_->set_pc(sim_->get_pc() + 2 * SimInstruction::kInstrSize);
529 debug();
530 }
532 int32_t
533 ArmDebugger::getRegisterValue(int regnum)
534 {
535 if (regnum == Registers::pc)
536 return sim_->get_pc();
537 return sim_->get_register(regnum);
538 }
540 double
541 ArmDebugger::getRegisterPairDoubleValue(int regnum)
542 {
543 return sim_->get_double_from_register_pair(regnum);
544 }
546 double
547 ArmDebugger::getVFPDoubleRegisterValue(int regnum)
548 {
549 return sim_->get_double_from_d_register(regnum);
550 }
552 bool
553 ArmDebugger::getValue(const char *desc, int32_t *value)
554 {
555 Register reg = Register::FromName(desc);
556 if (reg != InvalidReg) {
557 *value = getRegisterValue(reg.code());
558 return true;
559 }
560 if (strncmp(desc, "0x", 2) == 0)
561 return sscanf(desc + 2, "%x", reinterpret_cast<uint32_t*>(value)) == 1;
562 return sscanf(desc, "%u", reinterpret_cast<uint32_t*>(value)) == 1;
563 }
565 bool
566 ArmDebugger::getVFPDoubleValue(const char *desc, double *value)
567 {
568 FloatRegister reg = FloatRegister::FromName(desc);
569 if (reg != InvalidFloatReg) {
570 *value = sim_->get_double_from_d_register(reg.code());
571 return true;
572 }
573 return false;
574 }
576 bool
577 ArmDebugger::setBreakpoint(SimInstruction *breakpc)
578 {
579 // Check if a breakpoint can be set. If not return without any side-effects.
580 if (sim_->break_pc_)
581 return false;
583 // Set the breakpoint.
584 sim_->break_pc_ = breakpc;
585 sim_->break_instr_ = breakpc->instructionBits();
586 // Not setting the breakpoint instruction in the code itself. It will be set
587 // when the debugger shell continues.
588 return true;
589 }
591 bool
592 ArmDebugger::deleteBreakpoint(SimInstruction *breakpc)
593 {
594 if (sim_->break_pc_ != nullptr)
595 sim_->break_pc_->setInstructionBits(sim_->break_instr_);
597 sim_->break_pc_ = nullptr;
598 sim_->break_instr_ = 0;
599 return true;
600 }
602 void
603 ArmDebugger::undoBreakpoints()
604 {
605 if (sim_->break_pc_)
606 sim_->break_pc_->setInstructionBits(sim_->break_instr_);
607 }
609 void
610 ArmDebugger::redoBreakpoints()
611 {
612 if (sim_->break_pc_)
613 sim_->break_pc_->setInstructionBits(kBreakpointInstr);
614 }
616 static char *
617 ReadLine(const char *prompt)
618 {
619 char *result = nullptr;
620 char line_buf[256];
621 int offset = 0;
622 bool keep_going = true;
623 fprintf(stdout, "%s", prompt);
624 fflush(stdout);
625 while (keep_going) {
626 if (fgets(line_buf, sizeof(line_buf), stdin) == nullptr) {
627 // fgets got an error. Just give up.
628 if (result)
629 js_delete(result);
630 return nullptr;
631 }
632 int len = strlen(line_buf);
633 if (len > 0 && line_buf[len - 1] == '\n') {
634 // Since we read a new line we are done reading the line. This
635 // will exit the loop after copying this buffer into the result.
636 keep_going = false;
637 }
638 if (!result) {
639 // Allocate the initial result and make room for the terminating '\0'
640 result = (char *)js_malloc(len + 1);
641 if (!result)
642 return nullptr;
643 } else {
644 // Allocate a new result with enough room for the new addition.
645 int new_len = offset + len + 1;
646 char *new_result = (char *)js_malloc(new_len);
647 if (!new_result)
648 return nullptr;
649 // Copy the existing input into the new array and set the new
650 // array as the result.
651 memcpy(new_result, result, offset * sizeof(char));
652 js_free(result);
653 result = new_result;
654 }
655 // Copy the newly read line into the result.
656 memcpy(result + offset, line_buf, len * sizeof(char));
657 offset += len;
658 }
660 MOZ_ASSERT(result);
661 result[offset] = '\0';
662 return result;
663 }
665 static void
666 DisassembleInstruction(uint32_t pc)
667 {
668 uint8_t *bytes = reinterpret_cast<uint8_t *>(pc);
669 char hexbytes[256];
670 sprintf(hexbytes, "0x%x 0x%x 0x%x 0x%x", bytes[0], bytes[1], bytes[2], bytes[3]);
671 char llvmcmd[1024];
672 sprintf(llvmcmd, "bash -c \"echo -n '%p'; echo '%s' | "
673 "llvm-mc -disassemble -arch=arm -mcpu=cortex-a9 | "
674 "grep -v pure_instructions | grep -v .text\"",
675 reinterpret_cast<void*>(pc), hexbytes);
676 system(llvmcmd);
677 }
679 void
680 ArmDebugger::debug()
681 {
682 intptr_t last_pc = -1;
683 bool done = false;
685 #define COMMAND_SIZE 63
686 #define ARG_SIZE 255
688 #define STR(a) #a
689 #define XSTR(a) STR(a)
691 char cmd[COMMAND_SIZE + 1];
692 char arg1[ARG_SIZE + 1];
693 char arg2[ARG_SIZE + 1];
694 char *argv[3] = { cmd, arg1, arg2 };
696 // make sure to have a proper terminating character if reaching the limit
697 cmd[COMMAND_SIZE] = 0;
698 arg1[ARG_SIZE] = 0;
699 arg2[ARG_SIZE] = 0;
701 // Undo all set breakpoints while running in the debugger shell. This will
702 // make them invisible to all commands.
703 undoBreakpoints();
705 while (!done && !sim_->has_bad_pc()) {
706 if (last_pc != sim_->get_pc()) {
707 DisassembleInstruction(sim_->get_pc());
708 last_pc = sim_->get_pc();
709 }
710 char *line = ReadLine("sim> ");
711 if (line == nullptr) {
712 break;
713 } else {
714 char *last_input = sim_->lastDebuggerInput();
715 if (strcmp(line, "\n") == 0 && last_input != nullptr) {
716 line = last_input;
717 } else {
718 // Ownership is transferred to sim_;
719 sim_->setLastDebuggerInput(line);
720 }
722 // Use sscanf to parse the individual parts of the command line. At the
723 // moment no command expects more than two parameters.
724 int argc = sscanf(line,
725 "%" XSTR(COMMAND_SIZE) "s "
726 "%" XSTR(ARG_SIZE) "s "
727 "%" XSTR(ARG_SIZE) "s",
728 cmd, arg1, arg2);
729 if (argc < 0) {
730 continue;
731 } else if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
732 sim_->instructionDecode(reinterpret_cast<SimInstruction *>(sim_->get_pc()));
733 sim_->icount_++;
734 } else if ((strcmp(cmd, "skip") == 0)) {
735 sim_->set_pc(sim_->get_pc() + 4);
736 sim_->icount_++;
737 } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
738 // Execute the one instruction we broke at with breakpoints disabled.
739 sim_->instructionDecode(reinterpret_cast<SimInstruction *>(sim_->get_pc()));
740 sim_->icount_++;
741 // Leave the debugger shell.
742 done = true;
743 } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
744 if (argc == 2 || (argc == 3 && strcmp(arg2, "fp") == 0)) {
745 int32_t value;
746 double dvalue;
747 if (strcmp(arg1, "all") == 0) {
748 for (uint32_t i = 0; i < Registers::Total; i++) {
749 value = getRegisterValue(i);
750 printf("%3s: 0x%08x %10d", Registers::GetName(i), value, value);
751 if ((argc == 3 && strcmp(arg2, "fp") == 0) &&
752 i < 8 &&
753 (i % 2) == 0) {
754 dvalue = getRegisterPairDoubleValue(i);
755 printf(" (%f)\n", dvalue);
756 } else {
757 printf("\n");
758 }
759 }
760 for (uint32_t i = 0; i < FloatRegisters::Total; i++) {
761 dvalue = getVFPDoubleRegisterValue(i);
762 uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
763 printf("%3s: %f 0x%08x %08x\n",
764 FloatRegister::FromCode(i).name(),
765 dvalue,
766 static_cast<uint32_t>(as_words >> 32),
767 static_cast<uint32_t>(as_words & 0xffffffff));
768 }
769 } else {
770 if (getValue(arg1, &value)) {
771 printf("%s: 0x%08x %d \n", arg1, value, value);
772 } else if (getVFPDoubleValue(arg1, &dvalue)) {
773 uint64_t as_words = mozilla::BitwiseCast<uint64_t>(dvalue);
774 printf("%s: %f 0x%08x %08x\n",
775 arg1,
776 dvalue,
777 static_cast<uint32_t>(as_words >> 32),
778 static_cast<uint32_t>(as_words & 0xffffffff));
779 } else {
780 printf("%s unrecognized\n", arg1);
781 }
782 }
783 } else {
784 printf("print <register>\n");
785 }
786 } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
787 int32_t *cur = nullptr;
788 int32_t *end = nullptr;
789 int next_arg = 1;
791 if (strcmp(cmd, "stack") == 0) {
792 cur = reinterpret_cast<int32_t*>(sim_->get_register(Simulator::sp));
793 } else { // "mem"
794 int32_t value;
795 if (!getValue(arg1, &value)) {
796 printf("%s unrecognized\n", arg1);
797 continue;
798 }
799 cur = reinterpret_cast<int32_t*>(value);
800 next_arg++;
801 }
803 int32_t words;
804 if (argc == next_arg) {
805 words = 10;
806 } else {
807 if (!getValue(argv[next_arg], &words)) {
808 words = 10;
809 }
810 }
811 end = cur + words;
813 while (cur < end) {
814 printf(" %p: 0x%08x %10d", cur, *cur, *cur);
815 printf("\n");
816 cur++;
817 }
818 } else if (strcmp(cmd, "disasm") == 0 || strcmp(cmd, "di") == 0) {
819 uint8_t *cur = nullptr;
820 uint8_t *end = nullptr;
821 if (argc == 1) {
822 cur = reinterpret_cast<uint8_t *>(sim_->get_pc());
823 end = cur + (10 * SimInstruction::kInstrSize);
824 } else if (argc == 2) {
825 Register reg = Register::FromName(arg1);
826 if (reg != InvalidReg || strncmp(arg1, "0x", 2) == 0) {
827 // The argument is an address or a register name.
828 int32_t value;
829 if (getValue(arg1, &value)) {
830 cur = reinterpret_cast<uint8_t *>(value);
831 // Disassemble 10 instructions at <arg1>.
832 end = cur + (10 * SimInstruction::kInstrSize);
833 }
834 } else {
835 // The argument is the number of instructions.
836 int32_t value;
837 if (getValue(arg1, &value)) {
838 cur = reinterpret_cast<uint8_t *>(sim_->get_pc());
839 // Disassemble <arg1> instructions.
840 end = cur + (value * SimInstruction::kInstrSize);
841 }
842 }
843 } else {
844 int32_t value1;
845 int32_t value2;
846 if (getValue(arg1, &value1) && getValue(arg2, &value2)) {
847 cur = reinterpret_cast<uint8_t *>(value1);
848 end = cur + (value2 * SimInstruction::kInstrSize);
849 }
850 }
851 while (cur < end) {
852 DisassembleInstruction(uint32_t(cur));
853 cur += SimInstruction::kInstrSize;
854 }
855 } else if (strcmp(cmd, "gdb") == 0) {
856 printf("relinquishing control to gdb\n");
857 asm("int $3");
858 printf("regaining control from gdb\n");
859 } else if (strcmp(cmd, "break") == 0) {
860 if (argc == 2) {
861 int32_t value;
862 if (getValue(arg1, &value)) {
863 if (!setBreakpoint(reinterpret_cast<SimInstruction *>(value)))
864 printf("setting breakpoint failed\n");
865 } else {
866 printf("%s unrecognized\n", arg1);
867 }
868 } else {
869 printf("break <address>\n");
870 }
871 } else if (strcmp(cmd, "del") == 0) {
872 if (!deleteBreakpoint(nullptr)) {
873 printf("deleting breakpoint failed\n");
874 }
875 } else if (strcmp(cmd, "flags") == 0) {
876 printf("N flag: %d; ", sim_->n_flag_);
877 printf("Z flag: %d; ", sim_->z_flag_);
878 printf("C flag: %d; ", sim_->c_flag_);
879 printf("V flag: %d\n", sim_->v_flag_);
880 printf("INVALID OP flag: %d; ", sim_->inv_op_vfp_flag_);
881 printf("DIV BY ZERO flag: %d; ", sim_->div_zero_vfp_flag_);
882 printf("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_);
883 printf("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_);
884 printf("INEXACT flag: %d;\n", sim_->inexact_vfp_flag_);
885 } else if (strcmp(cmd, "stop") == 0) {
886 int32_t value;
887 intptr_t stop_pc = sim_->get_pc() - 2 * SimInstruction::kInstrSize;
888 SimInstruction *stop_instr = reinterpret_cast<SimInstruction *>(stop_pc);
889 SimInstruction *msg_address =
890 reinterpret_cast<SimInstruction *>(stop_pc + SimInstruction::kInstrSize);
891 if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) {
892 // Remove the current stop.
893 if (sim_->isStopInstruction(stop_instr)) {
894 stop_instr->setInstructionBits(kNopInstr);
895 msg_address->setInstructionBits(kNopInstr);
896 } else {
897 printf("Not at debugger stop.\n");
898 }
899 } else if (argc == 3) {
900 // Print information about all/the specified breakpoint(s).
901 if (strcmp(arg1, "info") == 0) {
902 if (strcmp(arg2, "all") == 0) {
903 printf("Stop information:\n");
904 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++)
905 sim_->printStopInfo(i);
906 } else if (getValue(arg2, &value)) {
907 sim_->printStopInfo(value);
908 } else {
909 printf("Unrecognized argument.\n");
910 }
911 } else if (strcmp(arg1, "enable") == 0) {
912 // Enable all/the specified breakpoint(s).
913 if (strcmp(arg2, "all") == 0) {
914 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++)
915 sim_->enableStop(i);
916 } else if (getValue(arg2, &value)) {
917 sim_->enableStop(value);
918 } else {
919 printf("Unrecognized argument.\n");
920 }
921 } else if (strcmp(arg1, "disable") == 0) {
922 // Disable all/the specified breakpoint(s).
923 if (strcmp(arg2, "all") == 0) {
924 for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) {
925 sim_->disableStop(i);
926 }
927 } else if (getValue(arg2, &value)) {
928 sim_->disableStop(value);
929 } else {
930 printf("Unrecognized argument.\n");
931 }
932 }
933 } else {
934 printf("Wrong usage. Use help command for more information.\n");
935 }
936 } else if ((strcmp(cmd, "h") == 0) || (strcmp(cmd, "help") == 0)) {
937 printf("cont\n");
938 printf(" continue execution (alias 'c')\n");
939 printf("skip\n");
940 printf(" skip one instruction (set pc to next instruction)\n");
941 printf("stepi\n");
942 printf(" step one instruction (alias 'si')\n");
943 printf("print <register>\n");
944 printf(" print register content (alias 'p')\n");
945 printf(" use register name 'all' to print all registers\n");
946 printf(" add argument 'fp' to print register pair double values\n");
947 printf("flags\n");
948 printf(" print flags\n");
949 printf("stack [<words>]\n");
950 printf(" dump stack content, default dump 10 words)\n");
951 printf("mem <address> [<words>]\n");
952 printf(" dump memory content, default dump 10 words)\n");
953 printf("disasm [<instructions>]\n");
954 printf("disasm [<address/register>]\n");
955 printf("disasm [[<address/register>] <instructions>]\n");
956 printf(" disassemble code, default is 10 instructions\n");
957 printf(" from pc (alias 'di')\n");
958 printf("gdb\n");
959 printf(" enter gdb\n");
960 printf("break <address>\n");
961 printf(" set a break point on the address\n");
962 printf("del\n");
963 printf(" delete the breakpoint\n");
964 printf("stop feature:\n");
965 printf(" Description:\n");
966 printf(" Stops are debug instructions inserted by\n");
967 printf(" the Assembler::stop() function.\n");
968 printf(" When hitting a stop, the Simulator will\n");
969 printf(" stop and and give control to the ArmDebugger.\n");
970 printf(" The first %d stop codes are watched:\n",
971 Simulator::kNumOfWatchedStops);
972 printf(" - They can be enabled / disabled: the Simulator\n");
973 printf(" will / won't stop when hitting them.\n");
974 printf(" - The Simulator keeps track of how many times they \n");
975 printf(" are met. (See the info command.) Going over a\n");
976 printf(" disabled stop still increases its counter. \n");
977 printf(" Commands:\n");
978 printf(" stop info all/<code> : print infos about number <code>\n");
979 printf(" or all stop(s).\n");
980 printf(" stop enable/disable all/<code> : enables / disables\n");
981 printf(" all or number <code> stop(s)\n");
982 printf(" stop unstop\n");
983 printf(" ignore the stop instruction at the current location\n");
984 printf(" from now on\n");
985 } else {
986 printf("Unknown command: %s\n", cmd);
987 }
988 }
989 }
991 // Add all the breakpoints back to stop execution and enter the debugger
992 // shell when hit.
993 redoBreakpoints();
995 #undef COMMAND_SIZE
996 #undef ARG_SIZE
998 #undef STR
999 #undef XSTR
1000 }
1002 static bool
1003 AllOnOnePage(uintptr_t start, int size)
1004 {
1005 intptr_t start_page = (start & ~CachePage::kPageMask);
1006 intptr_t end_page = ((start + size) & ~CachePage::kPageMask);
1007 return start_page == end_page;
1008 }
1010 static CachePage *
1011 GetCachePage(SimulatorRuntime::ICacheMap &i_cache, void *page)
1012 {
1013 MOZ_ASSERT(Simulator::ICacheCheckingEnabled);
1015 SimulatorRuntime::ICacheMap::AddPtr p = i_cache.lookupForAdd(page);
1016 if (p)
1017 return p->value();
1019 CachePage *new_page = js_new<CachePage>();
1020 if (!i_cache.add(p, page, new_page))
1021 return nullptr;
1022 return new_page;
1023 }
1025 // Flush from start up to and not including start + size.
1026 static void
1027 FlushOnePage(SimulatorRuntime::ICacheMap &i_cache, intptr_t start, int size)
1028 {
1029 MOZ_ASSERT(size <= CachePage::kPageSize);
1030 MOZ_ASSERT(AllOnOnePage(start, size - 1));
1031 MOZ_ASSERT((start & CachePage::kLineMask) == 0);
1032 MOZ_ASSERT((size & CachePage::kLineMask) == 0);
1034 void *page = reinterpret_cast<void*>(start & (~CachePage::kPageMask));
1035 int offset = (start & CachePage::kPageMask);
1036 CachePage *cache_page = GetCachePage(i_cache, page);
1037 char *valid_bytemap = cache_page->validityByte(offset);
1038 memset(valid_bytemap, CachePage::LINE_INVALID, size >> CachePage::kLineShift);
1039 }
1041 static void
1042 FlushICache(SimulatorRuntime::ICacheMap &i_cache, void *start_addr, size_t size)
1043 {
1044 intptr_t start = reinterpret_cast<intptr_t>(start_addr);
1045 int intra_line = (start & CachePage::kLineMask);
1046 start -= intra_line;
1047 size += intra_line;
1048 size = ((size - 1) | CachePage::kLineMask) + 1;
1049 int offset = (start & CachePage::kPageMask);
1050 while (!AllOnOnePage(start, size - 1)) {
1051 int bytes_to_flush = CachePage::kPageSize - offset;
1052 FlushOnePage(i_cache, start, bytes_to_flush);
1053 start += bytes_to_flush;
1054 size -= bytes_to_flush;
1055 MOZ_ASSERT((start & CachePage::kPageMask) == 0);
1056 offset = 0;
1057 }
1058 if (size != 0)
1059 FlushOnePage(i_cache, start, size);
1060 }
1062 static void
1063 CheckICache(SimulatorRuntime::ICacheMap &i_cache, SimInstruction *instr)
1064 {
1065 intptr_t address = reinterpret_cast<intptr_t>(instr);
1066 void *page = reinterpret_cast<void*>(address & (~CachePage::kPageMask));
1067 void *line = reinterpret_cast<void*>(address & (~CachePage::kLineMask));
1068 int offset = (address & CachePage::kPageMask);
1069 CachePage* cache_page = GetCachePage(i_cache, page);
1070 char *cache_valid_byte = cache_page->validityByte(offset);
1071 bool cache_hit = (*cache_valid_byte == CachePage::LINE_VALID);
1072 char *cached_line = cache_page->cachedData(offset & ~CachePage::kLineMask);
1073 if (cache_hit) {
1074 // Check that the data in memory matches the contents of the I-cache.
1075 MOZ_ASSERT(memcmp(reinterpret_cast<void*>(instr),
1076 cache_page->cachedData(offset),
1077 SimInstruction::kInstrSize) == 0);
1078 } else {
1079 // Cache miss. Load memory into the cache.
1080 memcpy(cached_line, line, CachePage::kLineLength);
1081 *cache_valid_byte = CachePage::LINE_VALID;
1082 }
1083 }
1085 HashNumber
1086 SimulatorRuntime::ICacheHasher::hash(const Lookup &l)
1087 {
1088 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(l)) >> 2;
1089 }
1091 bool
1092 SimulatorRuntime::ICacheHasher::match(const Key &k, const Lookup &l)
1093 {
1094 MOZ_ASSERT((reinterpret_cast<intptr_t>(k) & CachePage::kPageMask) == 0);
1095 MOZ_ASSERT((reinterpret_cast<intptr_t>(l) & CachePage::kPageMask) == 0);
1096 return k == l;
1097 }
1099 void
1100 Simulator::setLastDebuggerInput(char *input)
1101 {
1102 js_free(lastDebuggerInput_);
1103 lastDebuggerInput_ = input;
1104 }
1106 void
1107 Simulator::FlushICache(void *start_addr, size_t size)
1108 {
1109 IonSpewCont(IonSpew_CacheFlush, "[%p %zx]", start_addr, size);
1110 if (!Simulator::ICacheCheckingEnabled)
1111 return;
1112 SimulatorRuntime *srt = Simulator::Current()->srt_;
1113 AutoLockSimulatorRuntime alsr(srt);
1114 js::jit::FlushICache(srt->icache(), start_addr, size);
1115 }
1117 Simulator::~Simulator()
1118 {
1119 js_free(stack_);
1120 }
1122 Simulator::Simulator(SimulatorRuntime *srt)
1123 : srt_(srt)
1124 {
1125 // Set up simulator support first. Some of this information is needed to
1126 // setup the architecture state.
1128 // Allocate 2MB for the stack. Note that we will only use 1MB, see also
1129 // Simulator::stackLimit().
1130 static const size_t stackSize = 2 * 1024*1024;
1131 stack_ = reinterpret_cast<char*>(js_malloc(stackSize));
1132 if (!stack_) {
1133 MOZ_ReportAssertionFailure("[unhandlable oom] Simulator stack", __FILE__, __LINE__);
1134 MOZ_CRASH();
1135 }
1136 pc_modified_ = false;
1137 icount_ = 0L;
1138 resume_pc_ = 0;
1139 break_pc_ = nullptr;
1140 break_instr_ = 0;
1142 // Set up architecture state.
1143 // All registers are initialized to zero to start with.
1144 for (int i = 0; i < num_registers; i++)
1145 registers_[i] = 0;
1147 n_flag_ = false;
1148 z_flag_ = false;
1149 c_flag_ = false;
1150 v_flag_ = false;
1152 for (int i = 0; i < num_d_registers * 2; i++)
1153 vfp_registers_[i] = 0;
1155 n_flag_FPSCR_ = false;
1156 z_flag_FPSCR_ = false;
1157 c_flag_FPSCR_ = false;
1158 v_flag_FPSCR_ = false;
1159 FPSCR_rounding_mode_ = SimRZ;
1160 FPSCR_default_NaN_mode_ = true;
1162 inv_op_vfp_flag_ = false;
1163 div_zero_vfp_flag_ = false;
1164 overflow_vfp_flag_ = false;
1165 underflow_vfp_flag_ = false;
1166 inexact_vfp_flag_ = false;
1168 // The sp is initialized to point to the bottom (high address) of the
1169 // allocated stack area. To be safe in potential stack underflows we leave
1170 // some buffer below.
1171 registers_[sp] = reinterpret_cast<int32_t>(stack_) + stackSize - 64;
1173 // The lr and pc are initialized to a known bad value that will cause an
1174 // access violation if the simulator ever tries to execute it.
1175 registers_[pc] = bad_lr;
1176 registers_[lr] = bad_lr;
1178 lastDebuggerInput_ = nullptr;
1179 }
1181 // When the generated code calls a VM function (masm.callWithABI) we need to
1182 // call that function instead of trying to execute it with the simulator
1183 // (because it's x86 code instead of arm code). We do that by redirecting the
1184 // VM call to a svc (Supervisor Call) instruction that is handled by the
1185 // simulator. We write the original destination of the jump just at a known
1186 // offset from the svc instruction so the simulator knows what to call.
1187 class Redirection
1188 {
1189 friend class SimulatorRuntime;
1191 Redirection(void *nativeFunction, ABIFunctionType type)
1192 : nativeFunction_(nativeFunction),
1193 swiInstruction_(Assembler::AL | (0xf * (1 << 24)) | kCallRtRedirected),
1194 type_(type),
1195 next_(nullptr)
1196 {
1197 Simulator *sim = Simulator::Current();
1198 SimulatorRuntime *srt = sim->srt_;
1199 next_ = srt->redirection();
1200 if (Simulator::ICacheCheckingEnabled)
1201 FlushICache(srt->icache(), addressOfSwiInstruction(), SimInstruction::kInstrSize);
1202 srt->setRedirection(this);
1203 }
1205 public:
1206 void *addressOfSwiInstruction() { return &swiInstruction_; }
1207 void *nativeFunction() const { return nativeFunction_; }
1208 ABIFunctionType type() const { return type_; }
1210 static Redirection *Get(void *nativeFunction, ABIFunctionType type) {
1211 Simulator *sim = Simulator::Current();
1212 AutoLockSimulatorRuntime alsr(sim->srt_);
1214 Redirection *current = sim->srt_->redirection();
1215 for (; current != nullptr; current = current->next_) {
1216 if (current->nativeFunction_ == nativeFunction) {
1217 MOZ_ASSERT(current->type() == type);
1218 return current;
1219 }
1220 }
1222 Redirection *redir = (Redirection *)js_malloc(sizeof(Redirection));
1223 if (!redir) {
1224 MOZ_ReportAssertionFailure("[unhandlable oom] Simulator redirection",
1225 __FILE__, __LINE__);
1226 MOZ_CRASH();
1227 }
1228 new(redir) Redirection(nativeFunction, type);
1229 return redir;
1230 }
1232 static Redirection *FromSwiInstruction(SimInstruction *swiInstruction) {
1233 uint8_t *addrOfSwi = reinterpret_cast<uint8_t*>(swiInstruction);
1234 uint8_t *addrOfRedirection = addrOfSwi - offsetof(Redirection, swiInstruction_);
1235 return reinterpret_cast<Redirection*>(addrOfRedirection);
1236 }
1238 private:
1239 void *nativeFunction_;
1240 uint32_t swiInstruction_;
1241 ABIFunctionType type_;
1242 Redirection *next_;
1243 };
1245 /* static */ void *
1246 Simulator::RedirectNativeFunction(void *nativeFunction, ABIFunctionType type)
1247 {
1248 Redirection *redirection = Redirection::Get(nativeFunction, type);
1249 return redirection->addressOfSwiInstruction();
1250 }
1252 SimulatorRuntime::~SimulatorRuntime()
1253 {
1254 Redirection *r = redirection_;
1255 while (r) {
1256 Redirection *next = r->next_;
1257 js_delete(r);
1258 r = next;
1259 }
1260 #ifdef JS_THREADSAFE
1261 if (lock_)
1262 PR_DestroyLock(lock_);
1263 #endif
1264 }
1266 // Sets the register in the architecture state. It will also deal with updating
1267 // Simulator internal state for special registers such as PC.
1268 void
1269 Simulator::set_register(int reg, int32_t value)
1270 {
1271 MOZ_ASSERT(reg >= 0 && reg < num_registers);
1272 if (reg == pc)
1273 pc_modified_ = true;
1274 registers_[reg] = value;
1275 }
1277 // Get the register from the architecture state. This function does handle
1278 // the special case of accessing the PC register.
1279 int32_t
1280 Simulator::get_register(int reg) const
1281 {
1282 MOZ_ASSERT(reg >= 0 && reg < num_registers);
1283 // Work around GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43949
1284 if (reg >= num_registers) return 0;
1285 return registers_[reg] + ((reg == pc) ? SimInstruction::kPCReadOffset : 0);
1286 }
1288 double
1289 Simulator::get_double_from_register_pair(int reg)
1290 {
1291 MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0);
1293 // Read the bits from the unsigned integer register_[] array
1294 // into the double precision floating point value and return it.
1295 double dm_val = 0.0;
1296 char buffer[2 * sizeof(vfp_registers_[0])];
1297 memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
1298 memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
1299 return dm_val;
1300 }
1302 void
1303 Simulator::set_register_pair_from_double(int reg, double *value)
1304 {
1305 MOZ_ASSERT(reg >= 0 && reg < num_registers && (reg % 2) == 0);
1306 memcpy(registers_ + reg, value, sizeof(*value));
1307 }
1309 void
1310 Simulator::set_dw_register(int dreg, const int *dbl)
1311 {
1312 MOZ_ASSERT(dreg >= 0 && dreg < num_d_registers);
1313 registers_[dreg] = dbl[0];
1314 registers_[dreg + 1] = dbl[1];
1315 }
1317 void
1318 Simulator::get_d_register(int dreg, uint64_t *value)
1319 {
1320 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
1321 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value));
1322 }
1324 void
1325 Simulator::set_d_register(int dreg, const uint64_t *value)
1326 {
1327 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
1328 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value));
1329 }
1331 void
1332 Simulator::get_d_register(int dreg, uint32_t *value)
1333 {
1334 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
1335 memcpy(value, vfp_registers_ + dreg * 2, sizeof(*value) * 2);
1336 }
1338 void
1339 Simulator::set_d_register(int dreg, const uint32_t *value)
1340 {
1341 MOZ_ASSERT(dreg >= 0 && dreg < int(FloatRegisters::Total));
1342 memcpy(vfp_registers_ + dreg * 2, value, sizeof(*value) * 2);
1343 }
1345 void
1346 Simulator::get_q_register(int qreg, uint64_t *value)
1347 {
1348 MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
1349 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 2);
1350 }
1352 void
1353 Simulator::set_q_register(int qreg, const uint64_t *value)
1354 {
1355 MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
1356 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 2);
1357 }
1359 void
1360 Simulator::get_q_register(int qreg, uint32_t *value)
1361 {
1362 MOZ_ASSERT(qreg >= 0 && qreg < num_q_registers);
1363 memcpy(value, vfp_registers_ + qreg * 4, sizeof(*value) * 4);
1364 }
1366 void
1367 Simulator::set_q_register(int qreg, const uint32_t *value)
1368 {
1369 MOZ_ASSERT((qreg >= 0) && (qreg < num_q_registers));
1370 memcpy(vfp_registers_ + qreg * 4, value, sizeof(*value) * 4);
1371 }
1373 void
1374 Simulator::set_pc(int32_t value)
1375 {
1376 pc_modified_ = true;
1377 registers_[pc] = value;
1378 }
1380 bool
1381 Simulator::has_bad_pc() const
1382 {
1383 return registers_[pc] == bad_lr || registers_[pc] == end_sim_pc;
1384 }
1386 // Raw access to the PC register without the special adjustment when reading.
1387 int32_t
1388 Simulator::get_pc() const
1389 {
1390 return registers_[pc];
1391 }
1393 void
1394 Simulator::set_s_register(int sreg, unsigned int value)
1395 {
1396 MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers);
1397 vfp_registers_[sreg] = value;
1398 }
1400 unsigned
1401 Simulator::get_s_register(int sreg) const
1402 {
1403 MOZ_ASSERT(sreg >= 0 && sreg < num_s_registers);
1404 return vfp_registers_[sreg];
1405 }
1407 template<class InputType, int register_size>
1408 void
1409 Simulator::setVFPRegister(int reg_index, const InputType &value)
1410 {
1411 MOZ_ASSERT(reg_index >= 0);
1412 MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers);
1413 MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::Total));
1415 char buffer[register_size * sizeof(vfp_registers_[0])];
1416 memcpy(buffer, &value, register_size * sizeof(vfp_registers_[0]));
1417 memcpy(&vfp_registers_[reg_index * register_size], buffer,
1418 register_size * sizeof(vfp_registers_[0]));
1419 }
1421 template<class ReturnType, int register_size>
1422 ReturnType Simulator::getFromVFPRegister(int reg_index)
1423 {
1424 MOZ_ASSERT(reg_index >= 0);
1425 MOZ_ASSERT_IF(register_size == 1, reg_index < num_s_registers);
1426 MOZ_ASSERT_IF(register_size == 2, reg_index < int(FloatRegisters::Total));
1428 ReturnType value = 0;
1429 char buffer[register_size * sizeof(vfp_registers_[0])];
1430 memcpy(buffer, &vfp_registers_[register_size * reg_index],
1431 register_size * sizeof(vfp_registers_[0]));
1432 memcpy(&value, buffer, register_size * sizeof(vfp_registers_[0]));
1433 return value;
1434 }
1436 void
1437 Simulator::getFpArgs(double *x, double *y, int32_t *z)
1438 {
1439 if (useHardFpABI()) {
1440 *x = get_double_from_d_register(0);
1441 *y = get_double_from_d_register(1);
1442 *z = get_register(0);
1443 } else {
1444 *x = get_double_from_register_pair(0);
1445 *y = get_double_from_register_pair(2);
1446 *z = get_register(2);
1447 }
1448 }
1450 void
1451 Simulator::setCallResultDouble(double result)
1452 {
1453 // The return value is either in r0/r1 or d0.
1454 if (useHardFpABI()) {
1455 char buffer[2 * sizeof(vfp_registers_[0])];
1456 memcpy(buffer, &result, sizeof(buffer));
1457 // Copy result to d0.
1458 memcpy(vfp_registers_, buffer, sizeof(buffer));
1459 } else {
1460 char buffer[2 * sizeof(registers_[0])];
1461 memcpy(buffer, &result, sizeof(buffer));
1462 // Copy result to r0 and r1.
1463 memcpy(registers_, buffer, sizeof(buffer));
1464 }
1465 }
1467 void
1468 Simulator::setCallResultFloat(float result)
1469 {
1470 if (useHardFpABI()) {
1471 char buffer[sizeof(registers_[0])];
1472 memcpy(buffer, &result, sizeof(buffer));
1473 // Copy result to s0.
1474 memcpy(vfp_registers_, buffer, sizeof(buffer));
1475 } else {
1476 char buffer[sizeof(registers_[0])];
1477 memcpy(buffer, &result, sizeof(buffer));
1478 // Copy result to r0.
1479 memcpy(registers_, buffer, sizeof(buffer));
1480 }
1481 }
1483 void
1484 Simulator::setCallResult(int64_t res)
1485 {
1486 set_register(r0, static_cast<int32_t>(res));
1487 set_register(r1, static_cast<int32_t>(res >> 32));
1488 }
1490 int
1491 Simulator::readW(int32_t addr, SimInstruction *instr)
1492 {
1493 // YARR emits unaligned loads, so we don't check for them here like the
1494 // other methods below.
1495 intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
1496 return *ptr;
1497 }
1499 void
1500 Simulator::writeW(int32_t addr, int value, SimInstruction *instr)
1501 {
1502 if ((addr & 3) == 0) {
1503 intptr_t *ptr = reinterpret_cast<intptr_t*>(addr);
1504 *ptr = value;
1505 } else {
1506 printf("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
1507 MOZ_CRASH();
1508 }
1509 }
1511 uint16_t
1512 Simulator::readHU(int32_t addr, SimInstruction *instr)
1513 {
1514 if ((addr & 1) == 0) {
1515 uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
1516 return *ptr;
1517 }
1518 printf("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
1519 MOZ_CRASH();
1520 return 0;
1521 }
1523 int16_t
1524 Simulator::readH(int32_t addr, SimInstruction *instr)
1525 {
1526 if ((addr & 1) == 0) {
1527 int16_t *ptr = reinterpret_cast<int16_t*>(addr);
1528 return *ptr;
1529 }
1530 printf("Unaligned signed halfword read at 0x%08x\n", addr);
1531 MOZ_CRASH();
1532 return 0;
1533 }
1535 void
1536 Simulator::writeH(int32_t addr, uint16_t value, SimInstruction *instr)
1537 {
1538 if ((addr & 1) == 0) {
1539 uint16_t *ptr = reinterpret_cast<uint16_t*>(addr);
1540 *ptr = value;
1541 } else {
1542 printf("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
1543 MOZ_CRASH();
1544 }
1545 }
1547 void
1548 Simulator::writeH(int32_t addr, int16_t value, SimInstruction *instr)
1549 {
1550 if ((addr & 1) == 0) {
1551 int16_t *ptr = reinterpret_cast<int16_t*>(addr);
1552 *ptr = value;
1553 } else {
1554 printf("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
1555 MOZ_CRASH();
1556 }
1557 }
1559 uint8_t
1560 Simulator::readBU(int32_t addr)
1561 {
1562 uint8_t *ptr = reinterpret_cast<uint8_t*>(addr);
1563 return *ptr;
1564 }
1566 int8_t
1567 Simulator::readB(int32_t addr)
1568 {
1569 int8_t *ptr = reinterpret_cast<int8_t*>(addr);
1570 return *ptr;
1571 }
1573 void
1574 Simulator::writeB(int32_t addr, uint8_t value)
1575 {
1576 uint8_t *ptr = reinterpret_cast<uint8_t*>(addr);
1577 *ptr = value;
1578 }
1580 void
1581 Simulator::writeB(int32_t addr, int8_t value)
1582 {
1583 int8_t *ptr = reinterpret_cast<int8_t*>(addr);
1584 *ptr = value;
1585 }
1587 int32_t *
1588 Simulator::readDW(int32_t addr)
1589 {
1590 if ((addr & 3) == 0) {
1591 int32_t *ptr = reinterpret_cast<int32_t*>(addr);
1592 return ptr;
1593 }
1594 printf("Unaligned read at 0x%08x\n", addr);
1595 MOZ_CRASH();
1596 return 0;
1597 }
1599 void
1600 Simulator::writeDW(int32_t addr, int32_t value1, int32_t value2)
1601 {
1602 if ((addr & 3) == 0) {
1603 int32_t *ptr = reinterpret_cast<int32_t*>(addr);
1604 *ptr++ = value1;
1605 *ptr = value2;
1606 } else {
1607 printf("Unaligned write at 0x%08x\n", addr);
1608 MOZ_CRASH();
1609 }
1610 }
1612 uintptr_t
1613 Simulator::stackLimit() const
1614 {
1615 // Leave a safety margin of 1MB to prevent overrunning the stack when
1616 // pushing values (total stack size is 2MB).
1617 return reinterpret_cast<uintptr_t>(stack_) + 1024 * 1024;
1618 }
1620 bool
1621 Simulator::overRecursed(uintptr_t newsp) const
1622 {
1623 if (newsp == 0)
1624 newsp = get_register(sp);
1625 return newsp <= stackLimit();
1626 }
1628 bool
1629 Simulator::overRecursedWithExtra(uint32_t extra) const
1630 {
1631 uintptr_t newsp = get_register(sp) - extra;
1632 return newsp <= stackLimit();
1633 }
1635 // Checks if the current instruction should be executed based on its
1636 // condition bits.
1637 bool
1638 Simulator::conditionallyExecute(SimInstruction *instr)
1639 {
1640 switch (instr->conditionField()) {
1641 case Assembler::EQ: return z_flag_;
1642 case Assembler::NE: return !z_flag_;
1643 case Assembler::CS: return c_flag_;
1644 case Assembler::CC: return !c_flag_;
1645 case Assembler::MI: return n_flag_;
1646 case Assembler::PL: return !n_flag_;
1647 case Assembler::VS: return v_flag_;
1648 case Assembler::VC: return !v_flag_;
1649 case Assembler::HI: return c_flag_ && !z_flag_;
1650 case Assembler::LS: return !c_flag_ || z_flag_;
1651 case Assembler::GE: return n_flag_ == v_flag_;
1652 case Assembler::LT: return n_flag_ != v_flag_;
1653 case Assembler::GT: return !z_flag_ && (n_flag_ == v_flag_);
1654 case Assembler::LE: return z_flag_ || (n_flag_ != v_flag_);
1655 case Assembler::AL: return true;
1656 default: MOZ_ASSUME_UNREACHABLE();
1657 }
1658 return false;
1659 }
1661 // Calculate and set the Negative and Zero flags.
1662 void
1663 Simulator::setNZFlags(int32_t val)
1664 {
1665 n_flag_ = (val < 0);
1666 z_flag_ = (val == 0);
1667 }
1669 // Set the Carry flag.
1670 void
1671 Simulator::setCFlag(bool val)
1672 {
1673 c_flag_ = val;
1674 }
1676 // Set the oVerflow flag.
1677 void
1678 Simulator::setVFlag(bool val)
1679 {
1680 v_flag_ = val;
1681 }
1683 // Calculate C flag value for additions.
1684 bool
1685 Simulator::carryFrom(int32_t left, int32_t right, int32_t carry)
1686 {
1687 uint32_t uleft = static_cast<uint32_t>(left);
1688 uint32_t uright = static_cast<uint32_t>(right);
1689 uint32_t urest = 0xffffffffU - uleft;
1690 return (uright > urest) ||
1691 (carry && (((uright + 1) > urest) || (uright > (urest - 1))));
1692 }
1694 // Calculate C flag value for subtractions.
1695 bool
1696 Simulator::borrowFrom(int32_t left, int32_t right)
1697 {
1698 uint32_t uleft = static_cast<uint32_t>(left);
1699 uint32_t uright = static_cast<uint32_t>(right);
1700 return (uright > uleft);
1701 }
1703 // Calculate V flag value for additions and subtractions.
1704 bool
1705 Simulator::overflowFrom(int32_t alu_out, int32_t left, int32_t right, bool addition)
1706 {
1707 bool overflow;
1708 if (addition) {
1709 // operands have the same sign
1710 overflow = ((left >= 0 && right >= 0) || (left < 0 && right < 0))
1711 // and operands and result have different sign
1712 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1713 } else {
1714 // operands have different signs
1715 overflow = ((left < 0 && right >= 0) || (left >= 0 && right < 0))
1716 // and first operand and result have different signs
1717 && ((left < 0 && alu_out >= 0) || (left >= 0 && alu_out < 0));
1718 }
1719 return overflow;
1720 }
1722 // Support for VFP comparisons.
1723 void
1724 Simulator::compute_FPSCR_Flags(double val1, double val2)
1725 {
1726 if (mozilla::IsNaN(val1) || mozilla::IsNaN(val2)) {
1727 n_flag_FPSCR_ = false;
1728 z_flag_FPSCR_ = false;
1729 c_flag_FPSCR_ = true;
1730 v_flag_FPSCR_ = true;
1731 // All non-NaN cases.
1732 } else if (val1 == val2) {
1733 n_flag_FPSCR_ = false;
1734 z_flag_FPSCR_ = true;
1735 c_flag_FPSCR_ = true;
1736 v_flag_FPSCR_ = false;
1737 } else if (val1 < val2) {
1738 n_flag_FPSCR_ = true;
1739 z_flag_FPSCR_ = false;
1740 c_flag_FPSCR_ = false;
1741 v_flag_FPSCR_ = false;
1742 } else {
1743 // Case when (val1 > val2).
1744 n_flag_FPSCR_ = false;
1745 z_flag_FPSCR_ = false;
1746 c_flag_FPSCR_ = true;
1747 v_flag_FPSCR_ = false;
1748 }
1749 }
1751 void
1752 Simulator::copy_FPSCR_to_APSR()
1753 {
1754 n_flag_ = n_flag_FPSCR_;
1755 z_flag_ = z_flag_FPSCR_;
1756 c_flag_ = c_flag_FPSCR_;
1757 v_flag_ = v_flag_FPSCR_;
1758 }
1760 // Addressing Mode 1 - Data-processing operands:
1761 // Get the value based on the shifter_operand with register.
1762 int32_t
1763 Simulator::getShiftRm(SimInstruction *instr, bool *carry_out)
1764 {
1765 ShiftType shift = instr->shifttypeValue();
1766 int shift_amount = instr->shiftAmountValue();
1767 int32_t result = get_register(instr->rmValue());
1768 if (instr->bit(4) == 0) {
1769 // By immediate.
1770 if (shift == ROR && shift_amount == 0) {
1771 MOZ_ASSUME_UNREACHABLE("NYI");
1772 return result;
1773 }
1774 if ((shift == LSR || shift == ASR) && shift_amount == 0)
1775 shift_amount = 32;
1776 switch (shift) {
1777 case ASR: {
1778 if (shift_amount == 0) {
1779 if (result < 0) {
1780 result = 0xffffffff;
1781 *carry_out = true;
1782 } else {
1783 result = 0;
1784 *carry_out = false;
1785 }
1786 } else {
1787 result >>= (shift_amount - 1);
1788 *carry_out = (result & 1) == 1;
1789 result >>= 1;
1790 }
1791 break;
1792 }
1794 case LSL: {
1795 if (shift_amount == 0) {
1796 *carry_out = c_flag_;
1797 } else {
1798 result <<= (shift_amount - 1);
1799 *carry_out = (result < 0);
1800 result <<= 1;
1801 }
1802 break;
1803 }
1805 case LSR: {
1806 if (shift_amount == 0) {
1807 result = 0;
1808 *carry_out = c_flag_;
1809 } else {
1810 uint32_t uresult = static_cast<uint32_t>(result);
1811 uresult >>= (shift_amount - 1);
1812 *carry_out = (uresult & 1) == 1;
1813 uresult >>= 1;
1814 result = static_cast<int32_t>(uresult);
1815 }
1816 break;
1817 }
1819 case ROR: {
1820 if (shift_amount == 0) {
1821 *carry_out = c_flag_;
1822 } else {
1823 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1824 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1825 result = right | left;
1826 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1827 }
1828 break;
1829 }
1831 default:
1832 MOZ_ASSUME_UNREACHABLE();
1833 break;
1834 }
1835 } else {
1836 // By register.
1837 int rs = instr->rsValue();
1838 shift_amount = get_register(rs) &0xff;
1839 switch (shift) {
1840 case ASR: {
1841 if (shift_amount == 0) {
1842 *carry_out = c_flag_;
1843 } else if (shift_amount < 32) {
1844 result >>= (shift_amount - 1);
1845 *carry_out = (result & 1) == 1;
1846 result >>= 1;
1847 } else {
1848 MOZ_ASSERT(shift_amount >= 32);
1849 if (result < 0) {
1850 *carry_out = true;
1851 result = 0xffffffff;
1852 } else {
1853 *carry_out = false;
1854 result = 0;
1855 }
1856 }
1857 break;
1858 }
1860 case LSL: {
1861 if (shift_amount == 0) {
1862 *carry_out = c_flag_;
1863 } else if (shift_amount < 32) {
1864 result <<= (shift_amount - 1);
1865 *carry_out = (result < 0);
1866 result <<= 1;
1867 } else if (shift_amount == 32) {
1868 *carry_out = (result & 1) == 1;
1869 result = 0;
1870 } else {
1871 MOZ_ASSERT(shift_amount > 32);
1872 *carry_out = false;
1873 result = 0;
1874 }
1875 break;
1876 }
1878 case LSR: {
1879 if (shift_amount == 0) {
1880 *carry_out = c_flag_;
1881 } else if (shift_amount < 32) {
1882 uint32_t uresult = static_cast<uint32_t>(result);
1883 uresult >>= (shift_amount - 1);
1884 *carry_out = (uresult & 1) == 1;
1885 uresult >>= 1;
1886 result = static_cast<int32_t>(uresult);
1887 } else if (shift_amount == 32) {
1888 *carry_out = (result < 0);
1889 result = 0;
1890 } else {
1891 *carry_out = false;
1892 result = 0;
1893 }
1894 break;
1895 }
1897 case ROR: {
1898 if (shift_amount == 0) {
1899 *carry_out = c_flag_;
1900 } else {
1901 uint32_t left = static_cast<uint32_t>(result) >> shift_amount;
1902 uint32_t right = static_cast<uint32_t>(result) << (32 - shift_amount);
1903 result = right | left;
1904 *carry_out = (static_cast<uint32_t>(result) >> 31) != 0;
1905 }
1906 break;
1907 }
1909 default:
1910 MOZ_ASSUME_UNREACHABLE();
1911 break;
1912 }
1913 }
1914 return result;
1915 }
1917 // Addressing Mode 1 - Data-processing operands:
1918 // Get the value based on the shifter_operand with immediate.
1919 int32_t
1920 Simulator::getImm(SimInstruction *instr, bool *carry_out)
1921 {
1922 int rotate = instr->rotateValue() * 2;
1923 int immed8 = instr->immed8Value();
1924 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate));
1925 *carry_out = (rotate == 0) ? c_flag_ : (imm < 0);
1926 return imm;
1927 }
1929 int32_t
1930 Simulator::processPU(SimInstruction *instr, int num_regs, int reg_size,
1931 intptr_t *start_address, intptr_t *end_address)
1932 {
1933 int rn = instr->rnValue();
1934 int32_t rn_val = get_register(rn);
1935 switch (instr->PUField()) {
1936 case da_x:
1937 MOZ_CRASH();
1938 break;
1939 case ia_x:
1940 *start_address = rn_val;
1941 *end_address = rn_val + (num_regs * reg_size) - reg_size;
1942 rn_val = rn_val + (num_regs * reg_size);
1943 break;
1944 case db_x:
1945 *start_address = rn_val - (num_regs * reg_size);
1946 *end_address = rn_val - reg_size;
1947 rn_val = *start_address;
1948 break;
1949 case ib_x:
1950 *start_address = rn_val + reg_size;
1951 *end_address = rn_val + (num_regs * reg_size);
1952 rn_val = *end_address;
1953 break;
1954 default:
1955 MOZ_ASSUME_UNREACHABLE();
1956 break;
1957 }
1958 return rn_val;
1959 }
1961 // Addressing Mode 4 - Load and Store Multiple
1962 void
1963 Simulator::handleRList(SimInstruction *instr, bool load)
1964 {
1965 int rlist = instr->rlistValue();
1966 int num_regs = mozilla::CountPopulation32(rlist);
1968 intptr_t start_address = 0;
1969 intptr_t end_address = 0;
1970 int32_t rn_val = processPU(instr, num_regs, sizeof(void *), &start_address, &end_address);
1971 intptr_t *address = reinterpret_cast<intptr_t*>(start_address);
1973 // Catch null pointers a little earlier.
1974 MOZ_ASSERT(start_address > 8191 || start_address < 0);
1976 int reg = 0;
1977 while (rlist != 0) {
1978 if ((rlist & 1) != 0) {
1979 if (load) {
1980 set_register(reg, *address);
1981 } else {
1982 *address = get_register(reg);
1983 }
1984 address += 1;
1985 }
1986 reg++;
1987 rlist >>= 1;
1988 }
1989 MOZ_ASSERT(end_address == ((intptr_t)address) - 4);
1990 if (instr->hasW())
1991 set_register(instr->rnValue(), rn_val);
1992 }
1994 // Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
1995 void
1996 Simulator::handleVList(SimInstruction *instr)
1997 {
1998 VFPRegPrecision precision = (instr->szValue() == 0) ? kSinglePrecision : kDoublePrecision;
1999 int operand_size = (precision == kSinglePrecision) ? 4 : 8;
2000 bool load = (instr->VLValue() == 0x1);
2002 int vd;
2003 int num_regs;
2004 vd = instr->VFPDRegValue(precision);
2005 if (precision == kSinglePrecision)
2006 num_regs = instr->immed8Value();
2007 else
2008 num_regs = instr->immed8Value() / 2;
2010 intptr_t start_address = 0;
2011 intptr_t end_address = 0;
2012 int32_t rn_val = processPU(instr, num_regs, operand_size, &start_address, &end_address);
2014 intptr_t *address = reinterpret_cast<intptr_t*>(start_address);
2015 for (int reg = vd; reg < vd + num_regs; reg++) {
2016 if (precision == kSinglePrecision) {
2017 if (load)
2018 set_s_register_from_sinteger(reg, readW(reinterpret_cast<int32_t>(address), instr));
2019 else
2020 writeW(reinterpret_cast<int32_t>(address), get_sinteger_from_s_register(reg), instr);
2021 address += 1;
2022 } else {
2023 if (load) {
2024 int32_t data[] = {
2025 readW(reinterpret_cast<int32_t>(address), instr),
2026 readW(reinterpret_cast<int32_t>(address + 1), instr)
2027 };
2028 double d;
2029 memcpy(&d, data, 8);
2030 set_d_register_from_double(reg, d);
2031 } else {
2032 int32_t data[2];
2033 double d = get_double_from_d_register(reg);
2034 memcpy(data, &d, 8);
2035 writeW(reinterpret_cast<int32_t>(address), data[0], instr);
2036 writeW(reinterpret_cast<int32_t>(address + 1), data[1], instr);
2037 }
2038 address += 2;
2039 }
2040 }
2041 MOZ_ASSERT(reinterpret_cast<intptr_t>(address) - operand_size == end_address);
2042 if (instr->hasW())
2043 set_register(instr->rnValue(), rn_val);
2044 }
2047 // Note: With the code below we assume that all runtime calls return a 64 bits
2048 // result. If they don't, the r1 result register contains a bogus value, which
2049 // is fine because it is caller-saved.
2050 typedef int64_t (*Prototype_General0)();
2051 typedef int64_t (*Prototype_General1)(int32_t arg0);
2052 typedef int64_t (*Prototype_General2)(int32_t arg0, int32_t arg1);
2053 typedef int64_t (*Prototype_General3)(int32_t arg0, int32_t arg1, int32_t arg2);
2054 typedef int64_t (*Prototype_General4)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3);
2055 typedef int64_t (*Prototype_General5)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
2056 int32_t arg4);
2057 typedef int64_t (*Prototype_General6)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
2058 int32_t arg4, int32_t arg5);
2059 typedef int64_t (*Prototype_General7)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
2060 int32_t arg4, int32_t arg5, int32_t arg6);
2061 typedef int64_t (*Prototype_General8)(int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3,
2062 int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7);
2064 typedef double (*Prototype_Double_None)();
2065 typedef double (*Prototype_Double_Double)(double arg0);
2066 typedef double (*Prototype_Double_Int)(int32_t arg0);
2067 typedef int32_t (*Prototype_Int_Double)(double arg0);
2068 typedef float (*Prototype_Float32_Float32)(float arg0);
2070 typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
2071 typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
2072 typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
2073 typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
2076 // Fill the volatile registers with scratch values.
2077 //
2078 // Some of the ABI calls assume that the float registers are not scratched, even
2079 // though the ABI defines them as volatile - a performance optimization. These are
2080 // all calls passing operands in integer registers, so for now the simulator does not
2081 // scratch any float registers for these calls. Should try to narrow it further in
2082 // future.
2083 //
2084 void
2085 Simulator::scratchVolatileRegisters(bool scratchFloat)
2086 {
2087 int32_t scratch_value = 0xa5a5a5a5 ^ uint32_t(icount_);
2088 set_register(r0, scratch_value);
2089 set_register(r1, scratch_value);
2090 set_register(r2, scratch_value);
2091 set_register(r3, scratch_value);
2092 set_register(r12, scratch_value); // Intra-Procedure-call scratch register
2093 set_register(r14, scratch_value); // Link register
2095 if (scratchFloat) {
2096 uint64_t scratch_value_d = 0x5a5a5a5a5a5a5a5aLU ^ uint64_t(icount_) ^ (uint64_t(icount_) << 30);
2097 for (uint32_t i = d0; i < d8; i++)
2098 set_d_register(i, &scratch_value_d);
2099 for (uint32_t i = d16; i < FloatRegisters::Total; i++)
2100 set_d_register(i, &scratch_value_d);
2101 }
2102 }
2104 // Software interrupt instructions are used by the simulator to call into C++.
2105 void
2106 Simulator::softwareInterrupt(SimInstruction *instr)
2107 {
2108 int svc = instr->svcValue();
2109 switch (svc) {
2110 case kCallRtRedirected: {
2111 Redirection *redirection = Redirection::FromSwiInstruction(instr);
2112 int32_t arg0 = get_register(r0);
2113 int32_t arg1 = get_register(r1);
2114 int32_t arg2 = get_register(r2);
2115 int32_t arg3 = get_register(r3);
2116 int32_t *stack_pointer = reinterpret_cast<int32_t*>(get_register(sp));
2117 int32_t arg4 = stack_pointer[0];
2118 int32_t arg5 = stack_pointer[1];
2120 int32_t saved_lr = get_register(lr);
2121 intptr_t external = reinterpret_cast<intptr_t>(redirection->nativeFunction());
2123 bool stack_aligned = (get_register(sp) & (StackAlignment - 1)) == 0;
2124 if (!stack_aligned) {
2125 fprintf(stderr, "Runtime call with unaligned stack!\n");
2126 MOZ_CRASH();
2127 }
2129 switch (redirection->type()) {
2130 case Args_General0: {
2131 Prototype_General0 target = reinterpret_cast<Prototype_General0>(external);
2132 int64_t result = target();
2133 scratchVolatileRegisters(/* scratchFloat = true */);
2134 setCallResult(result);
2135 break;
2136 }
2137 case Args_General1: {
2138 Prototype_General1 target = reinterpret_cast<Prototype_General1>(external);
2139 int64_t result = target(arg0);
2140 scratchVolatileRegisters(/* scratchFloat = true */);
2141 setCallResult(result);
2142 break;
2143 }
2144 case Args_General2: {
2145 Prototype_General2 target = reinterpret_cast<Prototype_General2>(external);
2146 int64_t result = target(arg0, arg1);
2147 // The ARM backend makes calls to __aeabi_idivmod and __aeabi_uidivmod assuming
2148 // that the float registers are non-volatile as a performance optimization, so the
2149 // float registers must not be scratch when calling these.
2150 bool scratchFloat = target != __aeabi_idivmod && target != __aeabi_uidivmod;
2151 scratchVolatileRegisters(/* scratchFloat = */ scratchFloat);
2152 setCallResult(result);
2153 break;
2154 }
2155 case Args_General3: {
2156 Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
2157 int64_t result = target(arg0, arg1, arg2);
2158 scratchVolatileRegisters(/* scratchFloat = true*/);
2159 setCallResult(result);
2160 break;
2161 }
2162 case Args_General4: {
2163 Prototype_General4 target = reinterpret_cast<Prototype_General4>(external);
2164 int64_t result = target(arg0, arg1, arg2, arg3);
2165 scratchVolatileRegisters(/* scratchFloat = true*/);
2166 setCallResult(result);
2167 break;
2168 }
2169 case Args_General5: {
2170 Prototype_General5 target = reinterpret_cast<Prototype_General5>(external);
2171 int64_t result = target(arg0, arg1, arg2, arg3, arg4);
2172 scratchVolatileRegisters(/* scratchFloat = true */);
2173 setCallResult(result);
2174 break;
2175 }
2176 case Args_General6: {
2177 Prototype_General6 target = reinterpret_cast<Prototype_General6>(external);
2178 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5);
2179 scratchVolatileRegisters(/* scratchFloat = true */);
2180 setCallResult(result);
2181 break;
2182 }
2183 case Args_General7: {
2184 Prototype_General7 target = reinterpret_cast<Prototype_General7>(external);
2185 int32_t arg6 = stack_pointer[2];
2186 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6);
2187 scratchVolatileRegisters(/* scratchFloat = true */);
2188 setCallResult(result);
2189 break;
2190 }
2191 case Args_General8: {
2192 Prototype_General8 target = reinterpret_cast<Prototype_General8>(external);
2193 int32_t arg6 = stack_pointer[2];
2194 int32_t arg7 = stack_pointer[3];
2195 int64_t result = target(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
2196 scratchVolatileRegisters(/* scratchFloat = true */);
2197 setCallResult(result);
2198 break;
2199 }
2200 case Args_Double_None: {
2201 Prototype_Double_None target = reinterpret_cast<Prototype_Double_None>(external);
2202 double dresult = target();
2203 scratchVolatileRegisters(/* scratchFloat = true */);
2204 setCallResultDouble(dresult);
2205 break;
2206 }
2207 case Args_Int_Double: {
2208 double dval0, dval1;
2209 int32_t ival;
2210 getFpArgs(&dval0, &dval1, &ival);
2211 Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
2212 int32_t res = target(dval0);
2213 scratchVolatileRegisters(/* scratchFloat = true */);
2214 set_register(r0, res);
2215 break;
2216 }
2217 case Args_Double_Double: {
2218 double dval0, dval1;
2219 int32_t ival;
2220 getFpArgs(&dval0, &dval1, &ival);
2221 Prototype_Double_Double target = reinterpret_cast<Prototype_Double_Double>(external);
2222 double dresult = target(dval0);
2223 scratchVolatileRegisters(/* scratchFloat = true */);
2224 setCallResultDouble(dresult);
2225 break;
2226 }
2227 case Args_Float32_Float32: {
2228 float fval0;
2229 if (useHardFpABI())
2230 fval0 = get_float_from_s_register(0);
2231 else
2232 fval0 = mozilla::BitwiseCast<float>(arg0);
2233 Prototype_Float32_Float32 target = reinterpret_cast<Prototype_Float32_Float32>(external);
2234 float fresult = target(fval0);
2235 scratchVolatileRegisters(/* scratchFloat = true */);
2236 setCallResultFloat(fresult);
2237 break;
2238 }
2239 case Args_Double_Int: {
2240 Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
2241 double dresult = target(arg0);
2242 scratchVolatileRegisters(/* scratchFloat = true */);
2243 setCallResultDouble(dresult);
2244 break;
2245 }
2246 case Args_Double_DoubleInt: {
2247 double dval0, dval1;
2248 int32_t ival;
2249 getFpArgs(&dval0, &dval1, &ival);
2250 Prototype_DoubleInt target = reinterpret_cast<Prototype_DoubleInt>(external);
2251 double dresult = target(dval0, ival);
2252 scratchVolatileRegisters(/* scratchFloat = true */);
2253 setCallResultDouble(dresult);
2254 break;
2255 }
2256 case Args_Double_DoubleDouble: {
2257 double dval0, dval1;
2258 int32_t ival;
2259 getFpArgs(&dval0, &dval1, &ival);
2260 Prototype_Double_DoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDouble>(external);
2261 double dresult = target(dval0, dval1);
2262 scratchVolatileRegisters(/* scratchFloat = true */);
2263 setCallResultDouble(dresult);
2264 break;
2265 }
2266 case Args_Double_IntDouble: {
2267 int32_t ival = get_register(0);
2268 double dval0;
2269 if (useHardFpABI())
2270 dval0 = get_double_from_d_register(0);
2271 else
2272 dval0 = get_double_from_register_pair(2);
2273 Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
2274 double dresult = target(ival, dval0);
2275 scratchVolatileRegisters(/* scratchFloat = true */);
2276 setCallResultDouble(dresult);
2277 break;
2278 }
2279 case Args_Int_IntDouble: {
2280 int32_t ival = get_register(0);
2281 double dval0;
2282 if (useHardFpABI())
2283 dval0 = get_double_from_d_register(0);
2284 else
2285 dval0 = get_double_from_register_pair(2);
2286 Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
2287 int32_t result = target(ival, dval0);
2288 scratchVolatileRegisters(/* scratchFloat = true */);
2289 set_register(r0, result);
2290 break;
2291 }
2292 default:
2293 MOZ_ASSUME_UNREACHABLE("call");
2294 }
2296 set_register(lr, saved_lr);
2297 set_pc(get_register(lr));
2298 break;
2299 }
2300 case kBreakpoint: {
2301 ArmDebugger dbg(this);
2302 dbg.debug();
2303 break;
2304 }
2305 default: { // Stop uses all codes greater than 1 << 23.
2306 if (svc >= (1 << 23)) {
2307 uint32_t code = svc & kStopCodeMask;
2308 if (isWatchedStop(code))
2309 increaseStopCounter(code);
2311 // Stop if it is enabled, otherwise go on jumping over the stop
2312 // and the message address.
2313 if (isEnabledStop(code)) {
2314 ArmDebugger dbg(this);
2315 dbg.stop(instr);
2316 } else {
2317 set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
2318 }
2319 } else {
2320 // This is not a valid svc code.
2321 MOZ_CRASH();
2322 break;
2323 }
2324 }
2325 }
2326 }
2328 double
2329 Simulator::canonicalizeNaN(double value)
2330 {
2331 return FPSCR_default_NaN_mode_ ? JS::CanonicalizeNaN(value) : value;
2332 }
2334 // Stop helper functions.
2335 bool
2336 Simulator::isStopInstruction(SimInstruction *instr)
2337 {
2338 return (instr->bits(27, 24) == 0xF) && (instr->svcValue() >= kStopCode);
2339 }
2341 bool Simulator::isWatchedStop(uint32_t code)
2342 {
2343 MOZ_ASSERT(code <= kMaxStopCode);
2344 return code < kNumOfWatchedStops;
2345 }
2347 bool
2348 Simulator::isEnabledStop(uint32_t code)
2349 {
2350 MOZ_ASSERT(code <= kMaxStopCode);
2351 // Unwatched stops are always enabled.
2352 return !isWatchedStop(code) || !(watched_stops_[code].count & kStopDisabledBit);
2353 }
2355 void
2356 Simulator::enableStop(uint32_t code)
2357 {
2358 MOZ_ASSERT(isWatchedStop(code));
2359 if (!isEnabledStop(code))
2360 watched_stops_[code].count &= ~kStopDisabledBit;
2361 }
2363 void
2364 Simulator::disableStop(uint32_t code)
2365 {
2366 MOZ_ASSERT(isWatchedStop(code));
2367 if (isEnabledStop(code))
2368 watched_stops_[code].count |= kStopDisabledBit;
2369 }
2371 void
2372 Simulator::increaseStopCounter(uint32_t code)
2373 {
2374 MOZ_ASSERT(code <= kMaxStopCode);
2375 MOZ_ASSERT(isWatchedStop(code));
2376 if ((watched_stops_[code].count & ~(1 << 31)) == 0x7fffffff) {
2377 printf("Stop counter for code %i has overflowed.\n"
2378 "Enabling this code and reseting the counter to 0.\n", code);
2379 watched_stops_[code].count = 0;
2380 enableStop(code);
2381 } else {
2382 watched_stops_[code].count++;
2383 }
2384 }
2386 // Print a stop status.
2387 void
2388 Simulator::printStopInfo(uint32_t code)
2389 {
2390 MOZ_ASSERT(code <= kMaxStopCode);
2391 if (!isWatchedStop(code)) {
2392 printf("Stop not watched.");
2393 } else {
2394 const char *state = isEnabledStop(code) ? "Enabled" : "Disabled";
2395 int32_t count = watched_stops_[code].count & ~kStopDisabledBit;
2396 // Don't print the state of unused breakpoints.
2397 if (count != 0) {
2398 if (watched_stops_[code].desc) {
2399 printf("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n",
2400 code, code, state, count, watched_stops_[code].desc);
2401 } else {
2402 printf("stop %i - 0x%x: \t%s, \tcounter = %i\n",
2403 code, code, state, count);
2404 }
2405 }
2406 }
2407 }
2409 // Instruction types 0 and 1 are both rolled into one function because they
2410 // only differ in the handling of the shifter_operand.
2411 void
2412 Simulator::decodeType01(SimInstruction *instr)
2413 {
2414 int type = instr->typeValue();
2415 if (type == 0 && instr->isSpecialType0()) {
2416 // Multiply instruction or extra loads and stores.
2417 if (instr->bits(7, 4) == 9) {
2418 if (instr->bit(24) == 0) {
2419 // Raw field decoding here. Multiply instructions have their Rd
2420 // in funny places.
2421 int rn = instr->rnValue();
2422 int rm = instr->rmValue();
2423 int rs = instr->rsValue();
2424 int32_t rs_val = get_register(rs);
2425 int32_t rm_val = get_register(rm);
2426 if (instr->bit(23) == 0) {
2427 if (instr->bit(21) == 0) {
2428 // The MUL instruction description (A 4.1.33) refers to Rd as being
2429 // the destination for the operation, but it confusingly uses the
2430 // Rn field to encode it.
2431 int rd = rn; // Remap the rn field to the Rd register.
2432 int32_t alu_out = rm_val * rs_val;
2433 set_register(rd, alu_out);
2434 if (instr->hasS())
2435 setNZFlags(alu_out);
2436 } else {
2437 int rd = instr->rdValue();
2438 int32_t acc_value = get_register(rd);
2439 if (instr->bit(22) == 0) {
2440 // The MLA instruction description (A 4.1.28) refers to the order
2441 // of registers as "Rd, Rm, Rs, Rn". But confusingly it uses the
2442 // Rn field to encode the Rd register and the Rd field to encode
2443 // the Rn register.
2444 int32_t mul_out = rm_val * rs_val;
2445 int32_t result = acc_value + mul_out;
2446 set_register(rn, result);
2447 } else {
2448 int32_t mul_out = rm_val * rs_val;
2449 int32_t result = acc_value - mul_out;
2450 set_register(rn, result);
2451 }
2452 }
2453 } else {
2454 // The signed/long multiply instructions use the terms RdHi and RdLo
2455 // when referring to the target registers. They are mapped to the Rn
2456 // and Rd fields as follows:
2457 // RdLo == Rd
2458 // RdHi == Rn (This is confusingly stored in variable rd here
2459 // because the mul instruction from above uses the
2460 // Rn field to encode the Rd register. Good luck figuring
2461 // this out without reading the ARM instruction manual
2462 // at a very detailed level.)
2463 int rd_hi = rn; // Remap the rn field to the RdHi register.
2464 int rd_lo = instr->rdValue();
2465 int32_t hi_res = 0;
2466 int32_t lo_res = 0;
2467 if (instr->bit(22) == 1) {
2468 int64_t left_op = static_cast<int32_t>(rm_val);
2469 int64_t right_op = static_cast<int32_t>(rs_val);
2470 uint64_t result = left_op * right_op;
2471 hi_res = static_cast<int32_t>(result >> 32);
2472 lo_res = static_cast<int32_t>(result & 0xffffffff);
2473 } else {
2474 // unsigned multiply
2475 uint64_t left_op = static_cast<uint32_t>(rm_val);
2476 uint64_t right_op = static_cast<uint32_t>(rs_val);
2477 uint64_t result = left_op * right_op;
2478 hi_res = static_cast<int32_t>(result >> 32);
2479 lo_res = static_cast<int32_t>(result & 0xffffffff);
2480 }
2481 set_register(rd_lo, lo_res);
2482 set_register(rd_hi, hi_res);
2483 if (instr->hasS())
2484 MOZ_CRASH();
2485 }
2486 } else {
2487 MOZ_CRASH(); // Not used atm.
2488 }
2489 } else {
2490 // extra load/store instructions
2491 int rd = instr->rdValue();
2492 int rn = instr->rnValue();
2493 int32_t rn_val = get_register(rn);
2494 int32_t addr = 0;
2495 if (instr->bit(22) == 0) {
2496 int rm = instr->rmValue();
2497 int32_t rm_val = get_register(rm);
2498 switch (instr->PUField()) {
2499 case da_x:
2500 MOZ_ASSERT(!instr->hasW());
2501 addr = rn_val;
2502 rn_val -= rm_val;
2503 set_register(rn, rn_val);
2504 break;
2505 case ia_x:
2506 MOZ_ASSERT(!instr->hasW());
2507 addr = rn_val;
2508 rn_val += rm_val;
2509 set_register(rn, rn_val);
2510 break;
2511 case db_x:
2512 rn_val -= rm_val;
2513 addr = rn_val;
2514 if (instr->hasW())
2515 set_register(rn, rn_val);
2516 break;
2517 case ib_x:
2518 rn_val += rm_val;
2519 addr = rn_val;
2520 if (instr->hasW())
2521 set_register(rn, rn_val);
2522 break;
2523 default:
2524 // The PU field is a 2-bit field.
2525 MOZ_CRASH();
2526 break;
2527 }
2528 } else {
2529 int32_t imm_val = (instr->immedHValue() << 4) | instr->immedLValue();
2530 switch (instr->PUField()) {
2531 case da_x:
2532 MOZ_ASSERT(!instr->hasW());
2533 addr = rn_val;
2534 rn_val -= imm_val;
2535 set_register(rn, rn_val);
2536 break;
2537 case ia_x:
2538 MOZ_ASSERT(!instr->hasW());
2539 addr = rn_val;
2540 rn_val += imm_val;
2541 set_register(rn, rn_val);
2542 break;
2543 case db_x:
2544 rn_val -= imm_val;
2545 addr = rn_val;
2546 if (instr->hasW())
2547 set_register(rn, rn_val);
2548 break;
2549 case ib_x:
2550 rn_val += imm_val;
2551 addr = rn_val;
2552 if (instr->hasW())
2553 set_register(rn, rn_val);
2554 break;
2555 default:
2556 // The PU field is a 2-bit field.
2557 MOZ_CRASH();
2558 break;
2559 }
2560 }
2561 if ((instr->bits(7, 4) & 0xd) == 0xd && instr->bit(20) == 0) {
2562 MOZ_ASSERT((rd % 2) == 0);
2563 if (instr->hasH()) {
2564 // The strd instruction.
2565 int32_t value1 = get_register(rd);
2566 int32_t value2 = get_register(rd+1);
2567 writeDW(addr, value1, value2);
2568 } else {
2569 // The ldrd instruction.
2570 int *rn_data = readDW(addr);
2571 set_dw_register(rd, rn_data);
2572 }
2573 } else if (instr->hasH()) {
2574 if (instr->hasSign()) {
2575 if (instr->hasL()) {
2576 int16_t val = readH(addr, instr);
2577 set_register(rd, val);
2578 } else {
2579 int16_t val = get_register(rd);
2580 writeH(addr, val, instr);
2581 }
2582 } else {
2583 if (instr->hasL()) {
2584 uint16_t val = readHU(addr, instr);
2585 set_register(rd, val);
2586 } else {
2587 uint16_t val = get_register(rd);
2588 writeH(addr, val, instr);
2589 }
2590 }
2591 } else {
2592 // signed byte loads
2593 MOZ_ASSERT(instr->hasSign());
2594 MOZ_ASSERT(instr->hasL());
2595 int8_t val = readB(addr);
2596 set_register(rd, val);
2597 }
2598 return;
2599 }
2600 } else if ((type == 0) && instr->isMiscType0()) {
2601 if (instr->bits(7, 4) == 0) {
2602 if (instr->bit(21) == 0) {
2603 // mrs
2604 int rd = instr->rdValue();
2605 uint32_t flags;
2606 if (instr->bit(22) == 0) {
2607 // CPSR. Note: The Q flag is not yet implemented!
2608 flags = (n_flag_ << 31) |
2609 (z_flag_ << 30) |
2610 (c_flag_ << 29) |
2611 (v_flag_ << 28);
2612 } else {
2613 // SPSR
2614 MOZ_CRASH();
2615 }
2616 set_register(rd, flags);
2617 } else {
2618 // msr
2619 if (instr->bits(27, 23) == 2) {
2620 // Register operand. For now we only emit mask 0b1100.
2621 int rm = instr->rmValue();
2622 uint32_t mask = instr->bits(19, 16);
2623 MOZ_ASSERT(mask == (3 << 2));
2625 uint32_t flags = get_register(rm);
2626 n_flag_ = (flags >> 31) & 1;
2627 z_flag_ = (flags >> 30) & 1;
2628 c_flag_ = (flags >> 29) & 1;
2629 v_flag_ = (flags >> 28) & 1;
2630 } else {
2631 MOZ_CRASH();
2632 }
2633 }
2634 } else if (instr->bits(22, 21) == 1) {
2635 int rm = instr->rmValue();
2636 switch (instr->bits(7, 4)) {
2637 case 1: // BX
2638 set_pc(get_register(rm));
2639 break;
2640 case 3: { // BLX
2641 uint32_t old_pc = get_pc();
2642 set_pc(get_register(rm));
2643 set_register(lr, old_pc + SimInstruction::kInstrSize);
2644 break;
2645 }
2646 case 7: { // BKPT
2647 ArmDebugger dbg(this);
2648 printf("Simulator hit BKPT.\n");
2649 dbg.debug();
2650 break;
2651 }
2652 default:
2653 MOZ_CRASH();
2654 }
2655 } else if (instr->bits(22, 21) == 3) {
2656 int rm = instr->rmValue();
2657 int rd = instr->rdValue();
2658 switch (instr->bits(7, 4)) {
2659 case 1: { // CLZ
2660 uint32_t bits = get_register(rm);
2661 int leading_zeros = 0;
2662 if (bits == 0)
2663 leading_zeros = 32;
2664 else
2665 leading_zeros = mozilla::CountLeadingZeroes32(bits);
2666 set_register(rd, leading_zeros);
2667 break;
2668 }
2669 default:
2670 MOZ_CRASH();
2671 break;
2672 }
2673 } else {
2674 printf("%08x\n", instr->instructionBits());
2675 MOZ_CRASH();
2676 }
2677 } else if ((type == 1) && instr->isNopType1()) {
2678 // NOP.
2679 } else {
2680 int rd = instr->rdValue();
2681 int rn = instr->rnValue();
2682 int32_t rn_val = get_register(rn);
2683 int32_t shifter_operand = 0;
2684 bool shifter_carry_out = 0;
2685 if (type == 0) {
2686 shifter_operand = getShiftRm(instr, &shifter_carry_out);
2687 } else {
2688 MOZ_ASSERT(instr->typeValue() == 1);
2689 shifter_operand = getImm(instr, &shifter_carry_out);
2690 }
2691 int32_t alu_out;
2692 switch (instr->opcodeField()) {
2693 case op_and:
2694 alu_out = rn_val & shifter_operand;
2695 set_register(rd, alu_out);
2696 if (instr->hasS()) {
2697 setNZFlags(alu_out);
2698 setCFlag(shifter_carry_out);
2699 }
2700 break;
2701 case op_eor:
2702 alu_out = rn_val ^ shifter_operand;
2703 set_register(rd, alu_out);
2704 if (instr->hasS()) {
2705 setNZFlags(alu_out);
2706 setCFlag(shifter_carry_out);
2707 }
2708 break;
2709 case op_sub:
2710 alu_out = rn_val - shifter_operand;
2711 set_register(rd, alu_out);
2712 if (instr->hasS()) {
2713 setNZFlags(alu_out);
2714 setCFlag(!borrowFrom(rn_val, shifter_operand));
2715 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false));
2716 }
2717 break;
2718 case op_rsb:
2719 alu_out = shifter_operand - rn_val;
2720 set_register(rd, alu_out);
2721 if (instr->hasS()) {
2722 setNZFlags(alu_out);
2723 setCFlag(!borrowFrom(shifter_operand, rn_val));
2724 setVFlag(overflowFrom(alu_out, shifter_operand, rn_val, false));
2725 }
2726 break;
2727 case op_add:
2728 alu_out = rn_val + shifter_operand;
2729 set_register(rd, alu_out);
2730 if (instr->hasS()) {
2731 setNZFlags(alu_out);
2732 setCFlag(carryFrom(rn_val, shifter_operand));
2733 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
2734 }
2735 break;
2736 case op_adc:
2737 alu_out = rn_val + shifter_operand + getCarry();
2738 set_register(rd, alu_out);
2739 if (instr->hasS()) {
2740 setNZFlags(alu_out);
2741 setCFlag(carryFrom(rn_val, shifter_operand, getCarry()));
2742 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
2743 }
2744 break;
2745 case op_sbc:
2746 case op_rsc:
2747 MOZ_CRASH();
2748 break;
2749 case op_tst:
2750 if (instr->hasS()) {
2751 alu_out = rn_val & shifter_operand;
2752 setNZFlags(alu_out);
2753 setCFlag(shifter_carry_out);
2754 } else {
2755 alu_out = instr->immedMovwMovtValue();
2756 set_register(rd, alu_out);
2757 }
2758 break;
2759 case op_teq:
2760 if (instr->hasS()) {
2761 alu_out = rn_val ^ shifter_operand;
2762 setNZFlags(alu_out);
2763 setCFlag(shifter_carry_out);
2764 } else {
2765 // Other instructions matching this pattern are handled in the
2766 // miscellaneous instructions part above.
2767 MOZ_CRASH();
2768 }
2769 break;
2770 case op_cmp:
2771 if (instr->hasS()) {
2772 alu_out = rn_val - shifter_operand;
2773 setNZFlags(alu_out);
2774 setCFlag(!borrowFrom(rn_val, shifter_operand));
2775 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, false));
2776 } else {
2777 alu_out = (get_register(rd) & 0xffff) |
2778 (instr->immedMovwMovtValue() << 16);
2779 set_register(rd, alu_out);
2780 }
2781 break;
2782 case op_cmn:
2783 if (instr->hasS()) {
2784 alu_out = rn_val + shifter_operand;
2785 setNZFlags(alu_out);
2786 setCFlag(carryFrom(rn_val, shifter_operand));
2787 setVFlag(overflowFrom(alu_out, rn_val, shifter_operand, true));
2788 } else {
2789 // Other instructions matching this pattern are handled in the
2790 // miscellaneous instructions part above.
2791 MOZ_CRASH();
2792 }
2793 break;
2794 case op_orr:
2795 alu_out = rn_val | shifter_operand;
2796 set_register(rd, alu_out);
2797 if (instr->hasS()) {
2798 setNZFlags(alu_out);
2799 setCFlag(shifter_carry_out);
2800 }
2801 break;
2802 case op_mov:
2803 alu_out = shifter_operand;
2804 set_register(rd, alu_out);
2805 if (instr->hasS()) {
2806 setNZFlags(alu_out);
2807 setCFlag(shifter_carry_out);
2808 }
2809 break;
2810 case op_bic:
2811 alu_out = rn_val & ~shifter_operand;
2812 set_register(rd, alu_out);
2813 if (instr->hasS()) {
2814 setNZFlags(alu_out);
2815 setCFlag(shifter_carry_out);
2816 }
2817 break;
2818 case op_mvn:
2819 alu_out = ~shifter_operand;
2820 set_register(rd, alu_out);
2821 if (instr->hasS()) {
2822 setNZFlags(alu_out);
2823 setCFlag(shifter_carry_out);
2824 }
2825 break;
2826 default:
2827 MOZ_CRASH();
2828 break;
2829 }
2830 }
2831 }
2833 void
2834 Simulator::decodeType2(SimInstruction *instr)
2835 {
2836 int rd = instr->rdValue();
2837 int rn = instr->rnValue();
2838 int32_t rn_val = get_register(rn);
2839 int32_t im_val = instr->offset12Value();
2840 int32_t addr = 0;
2841 switch (instr->PUField()) {
2842 case da_x:
2843 MOZ_ASSERT(!instr->hasW());
2844 addr = rn_val;
2845 rn_val -= im_val;
2846 set_register(rn, rn_val);
2847 break;
2848 case ia_x:
2849 MOZ_ASSERT(!instr->hasW());
2850 addr = rn_val;
2851 rn_val += im_val;
2852 set_register(rn, rn_val);
2853 break;
2854 case db_x:
2855 rn_val -= im_val;
2856 addr = rn_val;
2857 if (instr->hasW())
2858 set_register(rn, rn_val);
2859 break;
2860 case ib_x:
2861 rn_val += im_val;
2862 addr = rn_val;
2863 if (instr->hasW())
2864 set_register(rn, rn_val);
2865 break;
2866 default:
2867 MOZ_CRASH();
2868 break;
2869 }
2870 if (instr->hasB()) {
2871 if (instr->hasL()) {
2872 uint8_t val = readBU(addr);
2873 set_register(rd, val);
2874 } else {
2875 uint8_t val = get_register(rd);
2876 writeB(addr, val);
2877 }
2878 } else {
2879 if (instr->hasL())
2880 set_register(rd, readW(addr, instr));
2881 else
2882 writeW(addr, get_register(rd), instr);
2883 }
2884 }
2886 void
2887 Simulator::decodeType3(SimInstruction *instr)
2888 {
2889 int rd = instr->rdValue();
2890 int rn = instr->rnValue();
2891 int32_t rn_val = get_register(rn);
2892 bool shifter_carry_out = 0;
2893 int32_t shifter_operand = getShiftRm(instr, &shifter_carry_out);
2894 int32_t addr = 0;
2895 switch (instr->PUField()) {
2896 case da_x:
2897 MOZ_ASSERT(!instr->hasW());
2898 MOZ_CRASH();
2899 break;
2900 case ia_x: {
2901 if (instr->bit(4) == 0) {
2902 // Memop.
2903 } else {
2904 if (instr->bit(5) == 0) {
2905 switch (instr->bits(22, 21)) {
2906 case 0:
2907 if (instr->bit(20) == 0) {
2908 if (instr->bit(6) == 0) {
2909 // Pkhbt.
2910 uint32_t rn_val = get_register(rn);
2911 uint32_t rm_val = get_register(instr->rmValue());
2912 int32_t shift = instr->bits(11, 7);
2913 rm_val <<= shift;
2914 set_register(rd, (rn_val & 0xFFFF) | (rm_val & 0xFFFF0000U));
2915 } else {
2916 // Pkhtb.
2917 uint32_t rn_val = get_register(rn);
2918 int32_t rm_val = get_register(instr->rmValue());
2919 int32_t shift = instr->bits(11, 7);
2920 if (shift == 0)
2921 shift = 32;
2922 rm_val >>= shift;
2923 set_register(rd, (rn_val & 0xFFFF0000U) | (rm_val & 0xFFFF));
2924 }
2925 } else {
2926 MOZ_CRASH();
2927 }
2928 break;
2929 case 1:
2930 MOZ_CRASH();
2931 break;
2932 case 2:
2933 MOZ_CRASH();
2934 break;
2935 case 3: {
2936 // Usat.
2937 int32_t sat_pos = instr->bits(20, 16);
2938 int32_t sat_val = (1 << sat_pos) - 1;
2939 int32_t shift = instr->bits(11, 7);
2940 int32_t shift_type = instr->bit(6);
2941 int32_t rm_val = get_register(instr->rmValue());
2942 if (shift_type == 0) // LSL
2943 rm_val <<= shift;
2944 else // ASR
2945 rm_val >>= shift;
2947 // If saturation occurs, the Q flag should be set in the CPSR.
2948 // There is no Q flag yet, and no instruction (MRS) to read the
2949 // CPSR directly.
2950 if (rm_val > sat_val)
2951 rm_val = sat_val;
2952 else if (rm_val < 0)
2953 rm_val = 0;
2954 set_register(rd, rm_val);
2955 break;
2956 }
2957 }
2958 } else {
2959 switch (instr->bits(22, 21)) {
2960 case 0:
2961 MOZ_CRASH();
2962 break;
2963 case 1:
2964 MOZ_CRASH();
2965 break;
2966 case 2:
2967 if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
2968 if (instr->bits(19, 16) == 0xF) {
2969 // Uxtb16.
2970 uint32_t rm_val = get_register(instr->rmValue());
2971 int32_t rotate = instr->bits(11, 10);
2972 switch (rotate) {
2973 case 0:
2974 break;
2975 case 1:
2976 rm_val = (rm_val >> 8) | (rm_val << 24);
2977 break;
2978 case 2:
2979 rm_val = (rm_val >> 16) | (rm_val << 16);
2980 break;
2981 case 3:
2982 rm_val = (rm_val >> 24) | (rm_val << 8);
2983 break;
2984 }
2985 set_register(rd, (rm_val & 0xFF) | (rm_val & 0xFF0000));
2986 } else {
2987 MOZ_CRASH();
2988 }
2989 } else {
2990 MOZ_CRASH();
2991 }
2992 break;
2993 case 3:
2994 if ((instr->bit(20) == 0) && (instr->bits(9, 6) == 1)) {
2995 if (instr->bits(19, 16) == 0xF) {
2996 // Uxtb.
2997 uint32_t rm_val = get_register(instr->rmValue());
2998 int32_t rotate = instr->bits(11, 10);
2999 switch (rotate) {
3000 case 0:
3001 break;
3002 case 1:
3003 rm_val = (rm_val >> 8) | (rm_val << 24);
3004 break;
3005 case 2:
3006 rm_val = (rm_val >> 16) | (rm_val << 16);
3007 break;
3008 case 3:
3009 rm_val = (rm_val >> 24) | (rm_val << 8);
3010 break;
3011 }
3012 set_register(rd, (rm_val & 0xFF));
3013 } else {
3014 // Uxtab.
3015 uint32_t rn_val = get_register(rn);
3016 uint32_t rm_val = get_register(instr->rmValue());
3017 int32_t rotate = instr->bits(11, 10);
3018 switch (rotate) {
3019 case 0:
3020 break;
3021 case 1:
3022 rm_val = (rm_val >> 8) | (rm_val << 24);
3023 break;
3024 case 2:
3025 rm_val = (rm_val >> 16) | (rm_val << 16);
3026 break;
3027 case 3:
3028 rm_val = (rm_val >> 24) | (rm_val << 8);
3029 break;
3030 }
3031 set_register(rd, rn_val + (rm_val & 0xFF));
3032 }
3033 } else {
3034 MOZ_CRASH();
3035 }
3036 break;
3037 }
3038 }
3039 return;
3040 }
3041 break;
3042 }
3043 case db_x: { // sudiv
3044 if (instr->bit(22) == 0x0 && instr->bit(20) == 0x1 &&
3045 instr->bits(15,12) == 0x0f && instr->bits(7, 4) == 0x1) {
3046 if (!instr->hasW()) {
3047 // sdiv (in V8 notation matching ARM ISA format) rn = rm/rs
3048 int rm = instr->rmValue();
3049 int32_t rm_val = get_register(rm);
3050 int rs = instr->rsValue();
3051 int32_t rs_val = get_register(rs);
3052 int32_t ret_val = 0;
3053 MOZ_ASSERT(rs_val != 0);
3054 if ((rm_val == INT32_MIN) && (rs_val == -1))
3055 ret_val = INT32_MIN;
3056 else
3057 ret_val = rm_val / rs_val;
3058 set_register(rn, ret_val);
3059 return;
3060 } else {
3061 // udiv (in V8 notation matching ARM ISA format) rn = rm/rs
3062 int rm = instr->rmValue();
3063 uint32_t rm_val = get_register(rm);
3064 int rs = instr->rsValue();
3065 uint32_t rs_val = get_register(rs);
3066 uint32_t ret_val = 0;
3067 MOZ_ASSERT(rs_val != 0);
3068 ret_val = rm_val / rs_val;
3069 set_register(rn, ret_val);
3070 return;
3071 }
3072 }
3074 addr = rn_val - shifter_operand;
3075 if (instr->hasW())
3076 set_register(rn, addr);
3077 break;
3078 }
3079 case ib_x: {
3080 if (instr->hasW() && (instr->bits(6, 4) == 0x5)) {
3081 uint32_t widthminus1 = static_cast<uint32_t>(instr->bits(20, 16));
3082 uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7));
3083 uint32_t msbit = widthminus1 + lsbit;
3084 if (msbit <= 31) {
3085 if (instr->bit(22)) {
3086 // ubfx - unsigned bitfield extract.
3087 uint32_t rm_val = static_cast<uint32_t>(get_register(instr->rmValue()));
3088 uint32_t extr_val = rm_val << (31 - msbit);
3089 extr_val = extr_val >> (31 - widthminus1);
3090 set_register(instr->rdValue(), extr_val);
3091 } else {
3092 // sbfx - signed bitfield extract.
3093 int32_t rm_val = get_register(instr->rmValue());
3094 int32_t extr_val = rm_val << (31 - msbit);
3095 extr_val = extr_val >> (31 - widthminus1);
3096 set_register(instr->rdValue(), extr_val);
3097 }
3098 } else {
3099 MOZ_CRASH();
3100 }
3101 return;
3102 } else if (!instr->hasW() && (instr->bits(6, 4) == 0x1)) {
3103 uint32_t lsbit = static_cast<uint32_t>(instr->bits(11, 7));
3104 uint32_t msbit = static_cast<uint32_t>(instr->bits(20, 16));
3105 if (msbit >= lsbit) {
3106 // bfc or bfi - bitfield clear/insert.
3107 uint32_t rd_val =
3108 static_cast<uint32_t>(get_register(instr->rdValue()));
3109 uint32_t bitcount = msbit - lsbit + 1;
3110 uint32_t mask = (1 << bitcount) - 1;
3111 rd_val &= ~(mask << lsbit);
3112 if (instr->rmValue() != 15) {
3113 // bfi - bitfield insert.
3114 uint32_t rm_val =
3115 static_cast<uint32_t>(get_register(instr->rmValue()));
3116 rm_val &= mask;
3117 rd_val |= rm_val << lsbit;
3118 }
3119 set_register(instr->rdValue(), rd_val);
3120 } else {
3121 MOZ_CRASH();
3122 }
3123 return;
3124 } else {
3125 addr = rn_val + shifter_operand;
3126 if (instr->hasW())
3127 set_register(rn, addr);
3128 }
3129 break;
3130 }
3131 default:
3132 MOZ_CRASH();
3133 break;
3134 }
3135 if (instr->hasB()) {
3136 if (instr->hasL()) {
3137 uint8_t byte = readB(addr);
3138 set_register(rd, byte);
3139 } else {
3140 uint8_t byte = get_register(rd);
3141 writeB(addr, byte);
3142 }
3143 } else {
3144 if (instr->hasL())
3145 set_register(rd, readW(addr, instr));
3146 else
3147 writeW(addr, get_register(rd), instr);
3148 }
3149 }
3151 void
3152 Simulator::decodeType4(SimInstruction *instr)
3153 {
3154 MOZ_ASSERT(instr->bit(22) == 0); // Only allowed to be set in privileged mode.
3155 bool load = instr->hasL();
3156 handleRList(instr, load);
3157 }
3159 void
3160 Simulator::decodeType5(SimInstruction *instr)
3161 {
3162 int off = instr->sImmed24Value() << 2;
3163 intptr_t pc_address = get_pc();
3164 if (instr->hasLink())
3165 set_register(lr, pc_address + SimInstruction::kInstrSize);
3166 int pc_reg = get_register(pc);
3167 set_pc(pc_reg + off);
3168 }
3170 void
3171 Simulator::decodeType6(SimInstruction *instr)
3172 {
3173 decodeType6CoprocessorIns(instr);
3174 }
3176 void
3177 Simulator::decodeType7(SimInstruction *instr)
3178 {
3179 if (instr->bit(24) == 1)
3180 softwareInterrupt(instr);
3181 else
3182 decodeTypeVFP(instr);
3183 }
3185 void
3186 Simulator::decodeTypeVFP(SimInstruction *instr)
3187 {
3188 MOZ_ASSERT(instr->typeValue() == 7 && instr->bit(24) == 0);
3189 MOZ_ASSERT(instr->bits(11, 9) == 0x5);
3191 // Obtain double precision register codes.
3192 VFPRegPrecision precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
3193 int vm = instr->VFPMRegValue(precision);
3194 int vd = instr->VFPDRegValue(precision);
3195 int vn = instr->VFPNRegValue(precision);
3197 if (instr->bit(4) == 0) {
3198 if (instr->opc1Value() == 0x7) {
3199 // Other data processing instructions
3200 if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x1)) {
3201 // vmov register to register.
3202 if (instr->szValue() == 0x1) {
3203 int m = instr->VFPMRegValue(kDoublePrecision);
3204 int d = instr->VFPDRegValue(kDoublePrecision);
3205 set_d_register_from_double(d, get_double_from_d_register(m));
3206 } else {
3207 int m = instr->VFPMRegValue(kSinglePrecision);
3208 int d = instr->VFPDRegValue(kSinglePrecision);
3209 set_s_register_from_float(d, get_float_from_s_register(m));
3210 }
3211 } else if ((instr->opc2Value() == 0x0) && (instr->opc3Value() == 0x3)) {
3212 // vabs
3213 if (instr->szValue() == 0x1) {
3214 double dm_value = get_double_from_d_register(vm);
3215 double dd_value = std::fabs(dm_value);
3216 dd_value = canonicalizeNaN(dd_value);
3217 set_d_register_from_double(vd, dd_value);
3218 } else {
3219 float fm_value = get_float_from_s_register(vm);
3220 float fd_value = std::fabs(fm_value);
3221 fd_value = canonicalizeNaN(fd_value);
3222 set_s_register_from_float(vd, fd_value);
3223 }
3224 } else if ((instr->opc2Value() == 0x1) && (instr->opc3Value() == 0x1)) {
3225 // vneg
3226 if (instr->szValue() == 0x1) {
3227 double dm_value = get_double_from_d_register(vm);
3228 double dd_value = -dm_value;
3229 dd_value = canonicalizeNaN(dd_value);
3230 set_d_register_from_double(vd, dd_value);
3231 } else {
3232 float fm_value = get_float_from_s_register(vm);
3233 float fd_value = -fm_value;
3234 fd_value = canonicalizeNaN(fd_value);
3235 set_s_register_from_float(vd, fd_value);
3236 }
3237 } else if ((instr->opc2Value() == 0x7) && (instr->opc3Value() == 0x3)) {
3238 decodeVCVTBetweenDoubleAndSingle(instr);
3239 } else if ((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) {
3240 decodeVCVTBetweenFloatingPointAndInteger(instr);
3241 } else if ((instr->opc2Value() == 0xA) && (instr->opc3Value() == 0x3) &&
3242 (instr->bit(8) == 1)) {
3243 // vcvt.f64.s32 Dd, Dd, #<fbits>
3244 int fraction_bits = 32 - ((instr->bits(3, 0) << 1) | instr->bit(5));
3245 int fixed_value = get_sinteger_from_s_register(vd * 2);
3246 double divide = 1 << fraction_bits;
3247 set_d_register_from_double(vd, fixed_value / divide);
3248 } else if (((instr->opc2Value() >> 1) == 0x6) &&
3249 (instr->opc3Value() & 0x1)) {
3250 decodeVCVTBetweenFloatingPointAndInteger(instr);
3251 } else if (((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) &&
3252 (instr->opc3Value() & 0x1)) {
3253 decodeVCMP(instr);
3254 } else if (((instr->opc2Value() == 0x1)) && (instr->opc3Value() == 0x3)) {
3255 // vsqrt
3256 if (instr->szValue() == 0x1) {
3257 double dm_value = get_double_from_d_register(vm);
3258 double dd_value = std::sqrt(dm_value);
3259 dd_value = canonicalizeNaN(dd_value);
3260 set_d_register_from_double(vd, dd_value);
3261 } else {
3262 float fm_value = get_float_from_s_register(vm);
3263 float fd_value = std::sqrt(fm_value);
3264 fd_value = canonicalizeNaN(fd_value);
3265 set_s_register_from_float(vd, fd_value);
3266 }
3267 } else if (instr->opc3Value() == 0x0) {
3268 // vmov immediate.
3269 if (instr->szValue() == 0x1) {
3270 set_d_register_from_double(vd, instr->doubleImmedVmov());
3271 } else {
3272 // vmov.f32 immediate
3273 set_s_register_from_float(vd, instr->float32ImmedVmov());
3274 }
3275 } else {
3276 decodeVCVTBetweenFloatingPointAndIntegerFrac(instr);
3277 }
3278 } else if (instr->opc1Value() == 0x3) {
3279 if (instr->szValue() != 0x1) {
3280 if (instr->opc3Value() & 0x1) {
3281 // vsub
3282 float fn_value = get_float_from_s_register(vn);
3283 float fm_value = get_float_from_s_register(vm);
3284 float fd_value = fn_value - fm_value;
3285 fd_value = canonicalizeNaN(fd_value);
3286 set_s_register_from_float(vd, fd_value);
3287 } else {
3288 // vadd
3289 float fn_value = get_float_from_s_register(vn);
3290 float fm_value = get_float_from_s_register(vm);
3291 float fd_value = fn_value + fm_value;
3292 fd_value = canonicalizeNaN(fd_value);
3293 set_s_register_from_float(vd, fd_value);
3294 }
3295 } else {
3296 if (instr->opc3Value() & 0x1) {
3297 // vsub
3298 double dn_value = get_double_from_d_register(vn);
3299 double dm_value = get_double_from_d_register(vm);
3300 double dd_value = dn_value - dm_value;
3301 dd_value = canonicalizeNaN(dd_value);
3302 set_d_register_from_double(vd, dd_value);
3303 } else {
3304 // vadd
3305 double dn_value = get_double_from_d_register(vn);
3306 double dm_value = get_double_from_d_register(vm);
3307 double dd_value = dn_value + dm_value;
3308 dd_value = canonicalizeNaN(dd_value);
3309 set_d_register_from_double(vd, dd_value);
3310 }
3311 }
3312 } else if ((instr->opc1Value() == 0x2) && !(instr->opc3Value() & 0x1)) {
3313 // vmul
3314 if (instr->szValue() != 0x1) {
3315 float fn_value = get_float_from_s_register(vn);
3316 float fm_value = get_float_from_s_register(vm);
3317 float fd_value = fn_value * fm_value;
3318 fd_value = canonicalizeNaN(fd_value);
3319 set_s_register_from_float(vd, fd_value);
3320 } else {
3321 double dn_value = get_double_from_d_register(vn);
3322 double dm_value = get_double_from_d_register(vm);
3323 double dd_value = dn_value * dm_value;
3324 dd_value = canonicalizeNaN(dd_value);
3325 set_d_register_from_double(vd, dd_value);
3326 }
3327 } else if ((instr->opc1Value() == 0x0)) {
3328 // vmla, vmls
3329 const bool is_vmls = (instr->opc3Value() & 0x1);
3331 if (instr->szValue() != 0x1)
3332 MOZ_ASSUME_UNREACHABLE(); // Not used by V8.
3334 const double dd_val = get_double_from_d_register(vd);
3335 const double dn_val = get_double_from_d_register(vn);
3336 const double dm_val = get_double_from_d_register(vm);
3338 // Note: we do the mul and add/sub in separate steps to avoid getting a
3339 // result with too high precision.
3340 set_d_register_from_double(vd, dn_val * dm_val);
3341 if (is_vmls) {
3342 set_d_register_from_double(vd,
3343 canonicalizeNaN(dd_val - get_double_from_d_register(vd)));
3344 } else {
3345 set_d_register_from_double(vd,
3346 canonicalizeNaN(dd_val + get_double_from_d_register(vd)));
3347 }
3348 } else if ((instr->opc1Value() == 0x4) && !(instr->opc3Value() & 0x1)) {
3349 // vdiv
3350 if (instr->szValue() != 0x1) {
3351 float fn_value = get_float_from_s_register(vn);
3352 float fm_value = get_float_from_s_register(vm);
3353 float fd_value = fn_value / fm_value;
3354 div_zero_vfp_flag_ = (fm_value == 0);
3355 fd_value = canonicalizeNaN(fd_value);
3356 set_s_register_from_float(vd, fd_value);
3357 } else {
3358 double dn_value = get_double_from_d_register(vn);
3359 double dm_value = get_double_from_d_register(vm);
3360 double dd_value = dn_value / dm_value;
3361 div_zero_vfp_flag_ = (dm_value == 0);
3362 dd_value = canonicalizeNaN(dd_value);
3363 set_d_register_from_double(vd, dd_value);
3364 }
3365 } else {
3366 MOZ_CRASH();
3367 }
3368 } else {
3369 if (instr->VCValue() == 0x0 && instr->VAValue() == 0x0) {
3370 decodeVMOVBetweenCoreAndSinglePrecisionRegisters(instr);
3371 } else if ((instr->VLValue() == 0x0) &&
3372 (instr->VCValue() == 0x1) &&
3373 (instr->bit(23) == 0x0)) {
3374 // vmov (ARM core register to scalar)
3375 int vd = instr->bits(19, 16) | (instr->bit(7) << 4);
3376 double dd_value = get_double_from_d_register(vd);
3377 int32_t data[2];
3378 memcpy(data, &dd_value, 8);
3379 data[instr->bit(21)] = get_register(instr->rtValue());
3380 memcpy(&dd_value, data, 8);
3381 set_d_register_from_double(vd, dd_value);
3382 } else if ((instr->VLValue() == 0x1) &&
3383 (instr->VCValue() == 0x1) &&
3384 (instr->bit(23) == 0x0)) {
3385 // vmov (scalar to ARM core register)
3386 int vn = instr->bits(19, 16) | (instr->bit(7) << 4);
3387 double dn_value = get_double_from_d_register(vn);
3388 int32_t data[2];
3389 memcpy(data, &dn_value, 8);
3390 set_register(instr->rtValue(), data[instr->bit(21)]);
3391 } else if ((instr->VLValue() == 0x1) &&
3392 (instr->VCValue() == 0x0) &&
3393 (instr->VAValue() == 0x7) &&
3394 (instr->bits(19, 16) == 0x1)) {
3395 // vmrs
3396 uint32_t rt = instr->rtValue();
3397 if (rt == 0xF) {
3398 copy_FPSCR_to_APSR();
3399 } else {
3400 // Emulate FPSCR from the Simulator flags.
3401 uint32_t fpscr = (n_flag_FPSCR_ << 31) |
3402 (z_flag_FPSCR_ << 30) |
3403 (c_flag_FPSCR_ << 29) |
3404 (v_flag_FPSCR_ << 28) |
3405 (FPSCR_default_NaN_mode_ << 25) |
3406 (inexact_vfp_flag_ << 4) |
3407 (underflow_vfp_flag_ << 3) |
3408 (overflow_vfp_flag_ << 2) |
3409 (div_zero_vfp_flag_ << 1) |
3410 (inv_op_vfp_flag_ << 0) |
3411 (FPSCR_rounding_mode_);
3412 set_register(rt, fpscr);
3413 }
3414 } else if ((instr->VLValue() == 0x0) &&
3415 (instr->VCValue() == 0x0) &&
3416 (instr->VAValue() == 0x7) &&
3417 (instr->bits(19, 16) == 0x1)) {
3418 // vmsr
3419 uint32_t rt = instr->rtValue();
3420 if (rt == pc) {
3421 MOZ_CRASH();
3422 } else {
3423 uint32_t rt_value = get_register(rt);
3424 n_flag_FPSCR_ = (rt_value >> 31) & 1;
3425 z_flag_FPSCR_ = (rt_value >> 30) & 1;
3426 c_flag_FPSCR_ = (rt_value >> 29) & 1;
3427 v_flag_FPSCR_ = (rt_value >> 28) & 1;
3428 FPSCR_default_NaN_mode_ = (rt_value >> 25) & 1;
3429 inexact_vfp_flag_ = (rt_value >> 4) & 1;
3430 underflow_vfp_flag_ = (rt_value >> 3) & 1;
3431 overflow_vfp_flag_ = (rt_value >> 2) & 1;
3432 div_zero_vfp_flag_ = (rt_value >> 1) & 1;
3433 inv_op_vfp_flag_ = (rt_value >> 0) & 1;
3434 FPSCR_rounding_mode_ =
3435 static_cast<VFPRoundingMode>((rt_value) & kVFPRoundingModeMask);
3436 }
3437 } else {
3438 MOZ_CRASH();
3439 }
3440 }
3441 }
3443 void
3444 Simulator::decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction *instr)
3445 {
3446 MOZ_ASSERT(instr->bit(4) == 1 &&
3447 instr->VCValue() == 0x0 &&
3448 instr->VAValue() == 0x0);
3450 int t = instr->rtValue();
3451 int n = instr->VFPNRegValue(kSinglePrecision);
3452 bool to_arm_register = (instr->VLValue() == 0x1);
3453 if (to_arm_register) {
3454 int32_t int_value = get_sinteger_from_s_register(n);
3455 set_register(t, int_value);
3456 } else {
3457 int32_t rs_val = get_register(t);
3458 set_s_register_from_sinteger(n, rs_val);
3459 }
3460 }
3462 void
3463 Simulator::decodeVCMP(SimInstruction *instr)
3464 {
3465 MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7));
3466 MOZ_ASSERT(((instr->opc2Value() == 0x4) || (instr->opc2Value() == 0x5)) &&
3467 (instr->opc3Value() & 0x1));
3468 // Comparison.
3470 VFPRegPrecision precision = kSinglePrecision;
3471 if (instr->szValue() == 1)
3472 precision = kDoublePrecision;
3474 int d = instr->VFPDRegValue(precision);
3475 int m = 0;
3476 if (instr->opc2Value() == 0x4)
3477 m = instr->VFPMRegValue(precision);
3479 if (precision == kDoublePrecision) {
3480 double dd_value = get_double_from_d_register(d);
3481 double dm_value = 0.0;
3482 if (instr->opc2Value() == 0x4) {
3483 dm_value = get_double_from_d_register(m);
3484 }
3486 // Raise exceptions for quiet NaNs if necessary.
3487 if (instr->bit(7) == 1) {
3488 if (mozilla::IsNaN(dd_value))
3489 inv_op_vfp_flag_ = true;
3490 }
3491 compute_FPSCR_Flags(dd_value, dm_value);
3492 } else {
3493 float fd_value = get_float_from_s_register(d);
3494 float fm_value = 0.0;
3495 if (instr->opc2Value() == 0x4)
3496 fm_value = get_float_from_s_register(m);
3498 // Raise exceptions for quiet NaNs if necessary.
3499 if (instr->bit(7) == 1) {
3500 if (mozilla::IsNaN(fd_value))
3501 inv_op_vfp_flag_ = true;
3502 }
3503 compute_FPSCR_Flags(fd_value, fm_value);
3504 }
3505 }
3507 void
3508 Simulator::decodeVCVTBetweenDoubleAndSingle(SimInstruction *instr)
3509 {
3510 MOZ_ASSERT(instr->bit(4) == 0 && instr->opc1Value() == 0x7);
3511 MOZ_ASSERT(instr->opc2Value() == 0x7 && instr->opc3Value() == 0x3);
3513 VFPRegPrecision dst_precision = kDoublePrecision;
3514 VFPRegPrecision src_precision = kSinglePrecision;
3515 if (instr->szValue() == 1) {
3516 dst_precision = kSinglePrecision;
3517 src_precision = kDoublePrecision;
3518 }
3520 int dst = instr->VFPDRegValue(dst_precision);
3521 int src = instr->VFPMRegValue(src_precision);
3523 if (dst_precision == kSinglePrecision) {
3524 double val = get_double_from_d_register(src);
3525 set_s_register_from_float(dst, static_cast<float>(val));
3526 } else {
3527 float val = get_float_from_s_register(src);
3528 set_d_register_from_double(dst, static_cast<double>(val));
3529 }
3530 }
3532 static bool
3533 get_inv_op_vfp_flag(VFPRoundingMode mode, double val, bool unsigned_)
3534 {
3535 MOZ_ASSERT(mode == SimRN || mode == SimRM || mode == SimRZ);
3536 double max_uint = static_cast<double>(0xffffffffu);
3537 double max_int = static_cast<double>(INT32_MAX);
3538 double min_int = static_cast<double>(INT32_MIN);
3540 // Check for NaN.
3541 if (val != val)
3542 return true;
3544 // Check for overflow. This code works because 32bit integers can be
3545 // exactly represented by ieee-754 64bit floating-point values.
3546 switch (mode) {
3547 case SimRN:
3548 return unsigned_ ? (val >= (max_uint + 0.5)) ||
3549 (val < -0.5)
3550 : (val >= (max_int + 0.5)) ||
3551 (val < (min_int - 0.5));
3552 case SimRM:
3553 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3554 (val < 0)
3555 : (val >= (max_int + 1.0)) ||
3556 (val < min_int);
3557 case SimRZ:
3558 return unsigned_ ? (val >= (max_uint + 1.0)) ||
3559 (val <= -1)
3560 : (val >= (max_int + 1.0)) ||
3561 (val <= (min_int - 1.0));
3562 default:
3563 MOZ_CRASH();
3564 return true;
3565 }
3566 }
3568 // We call this function only if we had a vfp invalid exception.
3569 // It returns the correct saturated value.
3570 static int
3571 VFPConversionSaturate(double val, bool unsigned_res)
3572 {
3573 if (val != val) // NaN.
3574 return 0;
3575 if (unsigned_res)
3576 return (val < 0) ? 0 : 0xffffffffu;
3577 return (val < 0) ? INT32_MIN : INT32_MAX;
3578 }
3580 void
3581 Simulator::decodeVCVTBetweenFloatingPointAndInteger(SimInstruction *instr)
3582 {
3583 MOZ_ASSERT((instr->bit(4) == 0) && (instr->opc1Value() == 0x7) &&
3584 (instr->bits(27, 23) == 0x1D));
3585 MOZ_ASSERT(((instr->opc2Value() == 0x8) && (instr->opc3Value() & 0x1)) ||
3586 (((instr->opc2Value() >> 1) == 0x6) && (instr->opc3Value() & 0x1)));
3588 // Conversion between floating-point and integer.
3589 bool to_integer = (instr->bit(18) == 1);
3591 VFPRegPrecision src_precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
3593 if (to_integer) {
3594 // We are playing with code close to the C++ standard's limits below,
3595 // hence the very simple code and heavy checks.
3596 //
3597 // Note:
3598 // C++ defines default type casting from floating point to integer as
3599 // (close to) rounding toward zero ("fractional part discarded").
3601 int dst = instr->VFPDRegValue(kSinglePrecision);
3602 int src = instr->VFPMRegValue(src_precision);
3604 // Bit 7 in vcvt instructions indicates if we should use the FPSCR rounding
3605 // mode or the default Round to Zero mode.
3606 VFPRoundingMode mode = (instr->bit(7) != 1) ? FPSCR_rounding_mode_ : SimRZ;
3607 MOZ_ASSERT(mode == SimRM || mode == SimRZ || mode == SimRN);
3609 bool unsigned_integer = (instr->bit(16) == 0);
3610 bool double_precision = (src_precision == kDoublePrecision);
3612 double val = double_precision
3613 ? get_double_from_d_register(src)
3614 : get_float_from_s_register(src);
3616 int temp = unsigned_integer ? static_cast<uint32_t>(val) : static_cast<int32_t>(val);
3618 inv_op_vfp_flag_ = get_inv_op_vfp_flag(mode, val, unsigned_integer);
3620 double abs_diff = unsigned_integer
3621 ? std::fabs(val - static_cast<uint32_t>(temp))
3622 : std::fabs(val - temp);
3624 inexact_vfp_flag_ = (abs_diff != 0);
3626 if (inv_op_vfp_flag_) {
3627 temp = VFPConversionSaturate(val, unsigned_integer);
3628 } else {
3629 switch (mode) {
3630 case SimRN: {
3631 int val_sign = (val > 0) ? 1 : -1;
3632 if (abs_diff > 0.5) {
3633 temp += val_sign;
3634 } else if (abs_diff == 0.5) {
3635 // Round to even if exactly halfway.
3636 temp = ((temp % 2) == 0) ? temp : temp + val_sign;
3637 }
3638 break;
3639 }
3641 case SimRM:
3642 temp = temp > val ? temp - 1 : temp;
3643 break;
3645 case SimRZ:
3646 // Nothing to do.
3647 break;
3649 default:
3650 MOZ_CRASH();
3651 }
3652 }
3654 // Update the destination register.
3655 set_s_register_from_sinteger(dst, temp);
3656 } else {
3657 bool unsigned_integer = (instr->bit(7) == 0);
3658 int dst = instr->VFPDRegValue(src_precision);
3659 int src = instr->VFPMRegValue(kSinglePrecision);
3661 int val = get_sinteger_from_s_register(src);
3663 if (src_precision == kDoublePrecision) {
3664 if (unsigned_integer)
3665 set_d_register_from_double(dst, static_cast<double>(static_cast<uint32_t>(val)));
3666 else
3667 set_d_register_from_double(dst, static_cast<double>(val));
3668 } else {
3669 if (unsigned_integer)
3670 set_s_register_from_float(dst, static_cast<float>(static_cast<uint32_t>(val)));
3671 else
3672 set_s_register_from_float(dst, static_cast<float>(val));
3673 }
3674 }
3675 }
3677 // A VFPv3 specific instruction.
3678 void
3679 Simulator::decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction *instr)
3680 {
3681 MOZ_ASSERT(instr->bits(27, 24) == 0xE && instr->opc1Value() == 0x7 && instr->bit(19) == 1 &&
3682 instr->bit(17) == 1 && instr->bits(11,9) == 0x5 && instr->bit(6) == 1 &&
3683 instr->bit(4) == 0);
3685 int size = (instr->bit(7) == 1) ? 32 : 16;
3687 int fraction_bits = size - ((instr->bits(3, 0) << 1) | instr->bit(5));
3688 double mult = 1 << fraction_bits;
3690 MOZ_ASSERT(size == 32); // Only handling size == 32 for now.
3692 // Conversion between floating-point and integer.
3693 bool to_fixed = (instr->bit(18) == 1);
3695 VFPRegPrecision precision = (instr->szValue() == 1) ? kDoublePrecision : kSinglePrecision;
3697 if (to_fixed) {
3698 // We are playing with code close to the C++ standard's limits below,
3699 // hence the very simple code and heavy checks.
3700 //
3701 // Note: C++ defines default type casting from floating point to integer as
3702 // (close to) rounding toward zero ("fractional part discarded").
3704 int dst = instr->VFPDRegValue(precision);
3706 bool unsigned_integer = (instr->bit(16) == 1);
3707 bool double_precision = (precision == kDoublePrecision);
3709 double val = double_precision
3710 ? get_double_from_d_register(dst)
3711 : get_float_from_s_register(dst);
3713 // Scale value by specified number of fraction bits.
3714 val *= mult;
3716 // Rounding down towards zero. No need to account for the rounding error as this
3717 // instruction always rounds down towards zero. See SimRZ below.
3718 int temp = unsigned_integer ? static_cast<uint32_t>(val) : static_cast<int32_t>(val);
3720 inv_op_vfp_flag_ = get_inv_op_vfp_flag(SimRZ, val, unsigned_integer);
3722 double abs_diff = unsigned_integer
3723 ? std::fabs(val - static_cast<uint32_t>(temp))
3724 : std::fabs(val - temp);
3726 inexact_vfp_flag_ = (abs_diff != 0);
3728 if (inv_op_vfp_flag_)
3729 temp = VFPConversionSaturate(val, unsigned_integer);
3731 // Update the destination register.
3732 if (double_precision) {
3733 uint32_t dbl[2];
3734 dbl[0] = temp; dbl[1] = 0;
3735 set_d_register(dst, dbl);
3736 } else {
3737 set_s_register_from_sinteger(dst, temp);
3738 }
3739 } else {
3740 MOZ_ASSUME_UNREACHABLE(); // Not implemented, fixed to float.
3741 }
3742 }
3744 void
3745 Simulator::decodeType6CoprocessorIns(SimInstruction *instr)
3746 {
3747 MOZ_ASSERT(instr->typeValue() == 6);
3749 if (instr->coprocessorValue() == 0xA) {
3750 switch (instr->opcodeValue()) {
3751 case 0x8:
3752 case 0xA:
3753 case 0xC:
3754 case 0xE: { // Load and store single precision float to memory.
3755 int rn = instr->rnValue();
3756 int vd = instr->VFPDRegValue(kSinglePrecision);
3757 int offset = instr->immed8Value();
3758 if (!instr->hasU())
3759 offset = -offset;
3761 int32_t address = get_register(rn) + 4 * offset;
3762 if (instr->hasL()) {
3763 // Load double from memory: vldr.
3764 set_s_register_from_sinteger(vd, readW(address, instr));
3765 } else {
3766 // Store double to memory: vstr.
3767 writeW(address, get_sinteger_from_s_register(vd), instr);
3768 }
3769 break;
3770 }
3771 case 0x4:
3772 case 0x5:
3773 case 0x6:
3774 case 0x7:
3775 case 0x9:
3776 case 0xB:
3777 // Load/store multiple single from memory: vldm/vstm.
3778 handleVList(instr);
3779 break;
3780 default:
3781 MOZ_CRASH();
3782 }
3783 } else if (instr->coprocessorValue() == 0xB) {
3784 switch (instr->opcodeValue()) {
3785 case 0x2:
3786 // Load and store double to two GP registers
3787 if (instr->bits(7, 6) != 0 || instr->bit(4) != 1) {
3788 MOZ_CRASH(); // Not used atm.
3789 } else {
3790 int rt = instr->rtValue();
3791 int rn = instr->rnValue();
3792 int vm = instr->VFPMRegValue(kDoublePrecision);
3793 if (instr->hasL()) {
3794 int32_t data[2];
3795 double d = get_double_from_d_register(vm);
3796 memcpy(data, &d, 8);
3797 set_register(rt, data[0]);
3798 set_register(rn, data[1]);
3799 } else {
3800 int32_t data[] = { get_register(rt), get_register(rn) };
3801 double d;
3802 memcpy(&d, data, 8);
3803 set_d_register_from_double(vm, d);
3804 }
3805 }
3806 break;
3807 case 0x8:
3808 case 0xA:
3809 case 0xC:
3810 case 0xE: { // Load and store double to memory.
3811 int rn = instr->rnValue();
3812 int vd = instr->VFPDRegValue(kDoublePrecision);
3813 int offset = instr->immed8Value();
3814 if (!instr->hasU())
3815 offset = -offset;
3816 int32_t address = get_register(rn) + 4 * offset;
3817 if (instr->hasL()) {
3818 // Load double from memory: vldr.
3819 int32_t data[] = {
3820 readW(address, instr),
3821 readW(address + 4, instr)
3822 };
3823 double val;
3824 memcpy(&val, data, 8);
3825 set_d_register_from_double(vd, val);
3826 } else {
3827 // Store double to memory: vstr.
3828 int32_t data[2];
3829 double val = get_double_from_d_register(vd);
3830 memcpy(data, &val, 8);
3831 writeW(address, data[0], instr);
3832 writeW(address + 4, data[1], instr);
3833 }
3834 break;
3835 }
3836 case 0x4:
3837 case 0x5:
3838 case 0x6:
3839 case 0x7:
3840 case 0x9:
3841 case 0xB:
3842 // Load/store multiple double from memory: vldm/vstm.
3843 handleVList(instr);
3844 break;
3845 default:
3846 MOZ_CRASH();
3847 }
3848 } else {
3849 MOZ_CRASH();
3850 }
3851 }
3853 void
3854 Simulator::decodeSpecialCondition(SimInstruction *instr)
3855 {
3856 switch (instr->specialValue()) {
3857 case 5:
3858 if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 && instr->bit(4) == 1) {
3859 // vmovl signed
3860 int Vd = (instr->bit(22) << 4) | instr->vdValue();
3861 int Vm = (instr->bit(5) << 4) | instr->vmValue();
3862 int imm3 = instr->bits(21, 19);
3863 if (imm3 != 1 && imm3 != 2 && imm3 != 4)
3864 MOZ_CRASH();
3865 int esize = 8 * imm3;
3866 int elements = 64 / esize;
3867 int8_t from[8];
3868 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3869 int16_t to[8];
3870 int e = 0;
3871 while (e < elements) {
3872 to[e] = from[e];
3873 e++;
3874 }
3875 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3876 } else {
3877 MOZ_CRASH();
3878 }
3879 break;
3880 case 7:
3881 if (instr->bits(18, 16) == 0 && instr->bits(11, 6) == 0x28 && instr->bit(4) == 1) {
3882 // vmovl unsigned
3883 int Vd = (instr->bit(22) << 4) | instr->vdValue();
3884 int Vm = (instr->bit(5) << 4) | instr->vmValue();
3885 int imm3 = instr->bits(21, 19);
3886 if (imm3 != 1 && imm3 != 2 && imm3 != 4)
3887 MOZ_CRASH();
3888 int esize = 8 * imm3;
3889 int elements = 64 / esize;
3890 uint8_t from[8];
3891 get_d_register(Vm, reinterpret_cast<uint64_t*>(from));
3892 uint16_t to[8];
3893 int e = 0;
3894 while (e < elements) {
3895 to[e] = from[e];
3896 e++;
3897 }
3898 set_q_register(Vd, reinterpret_cast<uint64_t*>(to));
3899 } else {
3900 MOZ_CRASH();
3901 }
3902 break;
3903 case 8:
3904 if (instr->bits(21, 20) == 0) {
3905 // vst1
3906 int Vd = (instr->bit(22) << 4) | instr->vdValue();
3907 int Rn = instr->vnValue();
3908 int type = instr->bits(11, 8);
3909 int Rm = instr->vmValue();
3910 int32_t address = get_register(Rn);
3911 int regs = 0;
3912 switch (type) {
3913 case nlt_1:
3914 regs = 1;
3915 break;
3916 case nlt_2:
3917 regs = 2;
3918 break;
3919 case nlt_3:
3920 regs = 3;
3921 break;
3922 case nlt_4:
3923 regs = 4;
3924 break;
3925 default:
3926 MOZ_CRASH();
3927 break;
3928 }
3929 int r = 0;
3930 while (r < regs) {
3931 uint32_t data[2];
3932 get_d_register(Vd + r, data);
3933 writeW(address, data[0], instr);
3934 writeW(address + 4, data[1], instr);
3935 address += 8;
3936 r++;
3937 }
3938 if (Rm != 15) {
3939 if (Rm == 13)
3940 set_register(Rn, address);
3941 else
3942 set_register(Rn, get_register(Rn) + get_register(Rm));
3943 }
3944 } else if (instr->bits(21, 20) == 2) {
3945 // vld1
3946 int Vd = (instr->bit(22) << 4) | instr->vdValue();
3947 int Rn = instr->vnValue();
3948 int type = instr->bits(11, 8);
3949 int Rm = instr->vmValue();
3950 int32_t address = get_register(Rn);
3951 int regs = 0;
3952 switch (type) {
3953 case nlt_1:
3954 regs = 1;
3955 break;
3956 case nlt_2:
3957 regs = 2;
3958 break;
3959 case nlt_3:
3960 regs = 3;
3961 break;
3962 case nlt_4:
3963 regs = 4;
3964 break;
3965 default:
3966 MOZ_CRASH();
3967 break;
3968 }
3969 int r = 0;
3970 while (r < regs) {
3971 uint32_t data[2];
3972 data[0] = readW(address, instr);
3973 data[1] = readW(address + 4, instr);
3974 set_d_register(Vd + r, data);
3975 address += 8;
3976 r++;
3977 }
3978 if (Rm != 15) {
3979 if (Rm == 13)
3980 set_register(Rn, address);
3981 else
3982 set_register(Rn, get_register(Rn) + get_register(Rm));
3983 }
3984 } else {
3985 MOZ_CRASH();
3986 }
3987 break;
3988 case 0xA:
3989 case 0xB:
3990 if (instr->bits(22, 20) == 5 && instr->bits(15, 12) == 0xf) {
3991 // pld: ignore instruction.
3992 } else {
3993 MOZ_CRASH();
3994 }
3995 break;
3996 default:
3997 MOZ_CRASH();
3998 }
3999 }
4001 // Executes the current instruction.
4002 void
4003 Simulator::instructionDecode(SimInstruction *instr)
4004 {
4005 if (Simulator::ICacheCheckingEnabled) {
4006 AutoLockSimulatorRuntime alsr(srt_);
4007 CheckICache(srt_->icache(), instr);
4008 }
4010 pc_modified_ = false;
4012 static const uint32_t kSpecialCondition = 15 << 28;
4013 if (instr->conditionField() == kSpecialCondition) {
4014 decodeSpecialCondition(instr);
4015 } else if (conditionallyExecute(instr)) {
4016 switch (instr->typeValue()) {
4017 case 0:
4018 case 1:
4019 decodeType01(instr);
4020 break;
4021 case 2:
4022 decodeType2(instr);
4023 break;
4024 case 3:
4025 decodeType3(instr);
4026 break;
4027 case 4:
4028 decodeType4(instr);
4029 break;
4030 case 5:
4031 decodeType5(instr);
4032 break;
4033 case 6:
4034 decodeType6(instr);
4035 break;
4036 case 7:
4037 decodeType7(instr);
4038 break;
4039 default:
4040 MOZ_CRASH();
4041 break;
4042 }
4043 // If the instruction is a non taken conditional stop, we need to skip the
4044 // inlined message address.
4045 } else if (instr->isStop()) {
4046 set_pc(get_pc() + 2 * SimInstruction::kInstrSize);
4047 }
4048 if (!pc_modified_)
4049 set_register(pc, reinterpret_cast<int32_t>(instr) + SimInstruction::kInstrSize);
4050 }
4053 template<bool EnableStopSimAt>
4054 void
4055 Simulator::execute()
4056 {
4057 // Get the PC to simulate. Cannot use the accessor here as we need the
4058 // raw PC value and not the one used as input to arithmetic instructions.
4059 int program_counter = get_pc();
4060 AsmJSActivation *activation = TlsPerThreadData.get()->asmJSActivationStackFromOwnerThread();
4062 while (program_counter != end_sim_pc) {
4063 if (EnableStopSimAt && (icount_ == Simulator::StopSimAt)) {
4064 fprintf(stderr, "\nStopped simulation at icount %lld\n", icount_);
4065 ArmDebugger dbg(this);
4066 dbg.debug();
4067 } else {
4068 SimInstruction *instr = reinterpret_cast<SimInstruction *>(program_counter);
4069 instructionDecode(instr);
4070 icount_++;
4072 int32_t rpc = resume_pc_;
4073 if (MOZ_UNLIKELY(rpc != 0)) {
4074 // AsmJS signal handler ran and we have to adjust the pc.
4075 activation->setInterrupted((void *)get_pc());
4076 set_pc(rpc);
4077 resume_pc_ = 0;
4078 }
4079 }
4080 program_counter = get_pc();
4081 }
4082 }
4084 void
4085 Simulator::callInternal(uint8_t *entry)
4086 {
4087 // Prepare to execute the code at entry.
4088 set_register(pc, reinterpret_cast<int32_t>(entry));
4090 // Put down marker for end of simulation. The simulator will stop simulation
4091 // when the PC reaches this value. By saving the "end simulation" value into
4092 // the LR the simulation stops when returning to this call point.
4093 set_register(lr, end_sim_pc);
4095 // Remember the values of callee-saved registers.
4096 // The code below assumes that r9 is not used as sb (static base) in
4097 // simulator code and therefore is regarded as a callee-saved register.
4098 int32_t r4_val = get_register(r4);
4099 int32_t r5_val = get_register(r5);
4100 int32_t r6_val = get_register(r6);
4101 int32_t r7_val = get_register(r7);
4102 int32_t r8_val = get_register(r8);
4103 int32_t r9_val = get_register(r9);
4104 int32_t r10_val = get_register(r10);
4105 int32_t r11_val = get_register(r11);
4107 // Remember d8 to d15 which are callee-saved.
4108 uint64_t d8_val;
4109 get_d_register(d8, &d8_val);
4110 uint64_t d9_val;
4111 get_d_register(d9, &d9_val);
4112 uint64_t d10_val;
4113 get_d_register(d10, &d10_val);
4114 uint64_t d11_val;
4115 get_d_register(d11, &d11_val);
4116 uint64_t d12_val;
4117 get_d_register(d12, &d12_val);
4118 uint64_t d13_val;
4119 get_d_register(d13, &d13_val);
4120 uint64_t d14_val;
4121 get_d_register(d14, &d14_val);
4122 uint64_t d15_val;
4123 get_d_register(d15, &d15_val);
4125 // Set up the callee-saved registers with a known value. To be able to check
4126 // that they are preserved properly across JS execution.
4127 int32_t callee_saved_value = uint32_t(icount_);
4128 set_register(r4, callee_saved_value);
4129 set_register(r5, callee_saved_value);
4130 set_register(r6, callee_saved_value);
4131 set_register(r7, callee_saved_value);
4132 set_register(r8, callee_saved_value);
4133 set_register(r9, callee_saved_value);
4134 set_register(r10, callee_saved_value);
4135 set_register(r11, callee_saved_value);
4137 uint64_t callee_saved_value_d = uint64_t(icount_);
4138 set_d_register(d8, &callee_saved_value_d);
4139 set_d_register(d9, &callee_saved_value_d);
4140 set_d_register(d10, &callee_saved_value_d);
4141 set_d_register(d11, &callee_saved_value_d);
4142 set_d_register(d12, &callee_saved_value_d);
4143 set_d_register(d13, &callee_saved_value_d);
4144 set_d_register(d14, &callee_saved_value_d);
4145 set_d_register(d15, &callee_saved_value_d);
4147 // Start the simulation
4148 if (Simulator::StopSimAt != -1L)
4149 execute<true>();
4150 else
4151 execute<false>();
4153 // Check that the callee-saved registers have been preserved.
4154 MOZ_ASSERT(callee_saved_value == get_register(r4));
4155 MOZ_ASSERT(callee_saved_value == get_register(r5));
4156 MOZ_ASSERT(callee_saved_value == get_register(r6));
4157 MOZ_ASSERT(callee_saved_value == get_register(r7));
4158 MOZ_ASSERT(callee_saved_value == get_register(r8));
4159 MOZ_ASSERT(callee_saved_value == get_register(r9));
4160 MOZ_ASSERT(callee_saved_value == get_register(r10));
4161 MOZ_ASSERT(callee_saved_value == get_register(r11));
4163 uint64_t value;
4164 get_d_register(d8, &value);
4165 MOZ_ASSERT(callee_saved_value_d == value);
4166 get_d_register(d9, &value);
4167 MOZ_ASSERT(callee_saved_value_d == value);
4168 get_d_register(d10, &value);
4169 MOZ_ASSERT(callee_saved_value_d == value);
4170 get_d_register(d11, &value);
4171 MOZ_ASSERT(callee_saved_value_d == value);
4172 get_d_register(d12, &value);
4173 MOZ_ASSERT(callee_saved_value_d == value);
4174 get_d_register(d13, &value);
4175 MOZ_ASSERT(callee_saved_value_d == value);
4176 get_d_register(d14, &value);
4177 MOZ_ASSERT(callee_saved_value_d == value);
4178 get_d_register(d15, &value);
4179 MOZ_ASSERT(callee_saved_value_d == value);
4181 // Restore callee-saved registers with the original value.
4182 set_register(r4, r4_val);
4183 set_register(r5, r5_val);
4184 set_register(r6, r6_val);
4185 set_register(r7, r7_val);
4186 set_register(r8, r8_val);
4187 set_register(r9, r9_val);
4188 set_register(r10, r10_val);
4189 set_register(r11, r11_val);
4191 set_d_register(d8, &d8_val);
4192 set_d_register(d9, &d9_val);
4193 set_d_register(d10, &d10_val);
4194 set_d_register(d11, &d11_val);
4195 set_d_register(d12, &d12_val);
4196 set_d_register(d13, &d13_val);
4197 set_d_register(d14, &d14_val);
4198 set_d_register(d15, &d15_val);
4199 }
4201 int64_t
4202 Simulator::call(uint8_t* entry, int argument_count, ...)
4203 {
4204 va_list parameters;
4205 va_start(parameters, argument_count);
4207 // First four arguments passed in registers.
4208 MOZ_ASSERT(argument_count >= 2);
4209 set_register(r0, va_arg(parameters, int32_t));
4210 set_register(r1, va_arg(parameters, int32_t));
4211 if (argument_count >= 3)
4212 set_register(r2, va_arg(parameters, int32_t));
4213 if (argument_count >= 4)
4214 set_register(r3, va_arg(parameters, int32_t));
4216 // Remaining arguments passed on stack.
4217 int original_stack = get_register(sp);
4218 int entry_stack = original_stack;
4219 if (argument_count >= 4)
4220 entry_stack -= (argument_count - 4) * sizeof(int32_t);
4222 entry_stack &= ~StackAlignment;
4224 // Store remaining arguments on stack, from low to high memory.
4225 intptr_t *stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
4226 for (int i = 4; i < argument_count; i++)
4227 stack_argument[i - 4] = va_arg(parameters, int32_t);
4228 va_end(parameters);
4229 set_register(sp, entry_stack);
4231 callInternal(entry);
4233 // Pop stack passed arguments.
4234 MOZ_ASSERT(entry_stack == get_register(sp));
4235 set_register(sp, original_stack);
4237 int64_t result = (int64_t(get_register(r1)) << 32) | get_register(r0);
4238 return result;
4239 }
4241 Simulator *
4242 Simulator::Current()
4243 {
4244 PerThreadData *pt = TlsPerThreadData.get();
4245 Simulator *sim = pt->simulator();
4246 if (!sim) {
4247 sim = js_new<Simulator>(pt->simulatorRuntime());
4248 pt->setSimulator(sim);
4249 }
4251 return sim;
4252 }
4254 } // namespace jit
4255 } // namespace js
4257 js::jit::Simulator *
4258 js::PerThreadData::simulator() const
4259 {
4260 return simulator_;
4261 }
4263 void
4264 js::PerThreadData::setSimulator(js::jit::Simulator *sim)
4265 {
4266 simulator_ = sim;
4267 simulatorStackLimit_ = sim->stackLimit();
4268 }
4270 js::jit::SimulatorRuntime *
4271 js::PerThreadData::simulatorRuntime() const
4272 {
4273 return runtime_->simulatorRuntime();
4274 }
4276 uintptr_t *
4277 js::PerThreadData::addressOfSimulatorStackLimit()
4278 {
4279 return &simulatorStackLimit_;
4280 }
4282 js::jit::SimulatorRuntime *
4283 JSRuntime::simulatorRuntime() const
4284 {
4285 return simulatorRuntime_;
4286 }
4288 void
4289 JSRuntime::setSimulatorRuntime(js::jit::SimulatorRuntime *srt)
4290 {
4291 MOZ_ASSERT(!simulatorRuntime_);
4292 simulatorRuntime_ = srt;
4293 }