| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 // Declares a Simulator for MIPS instructions if we are not generating a native | |
| 6 // MIPS binary. This Simulator allows us to run and debug MIPS code generation | |
| 7 // on regular desktop machines. | |
| 8 // Dart calls into generated code by "calling" the InvokeDartCode stub, | |
| 9 // which will start execution in the Simulator or forwards to the real entry | |
| 10 // on a MIPS HW platform. | |
| 11 | |
| 12 #ifndef RUNTIME_VM_SIMULATOR_MIPS_H_ | |
| 13 #define RUNTIME_VM_SIMULATOR_MIPS_H_ | |
| 14 | |
| 15 #ifndef RUNTIME_VM_SIMULATOR_H_ | |
| 16 #error Do not include simulator_mips.h directly; use simulator.h. | |
| 17 #endif | |
| 18 | |
| 19 #include "vm/constants_mips.h" | |
| 20 | |
| 21 namespace dart { | |
| 22 | |
| 23 class Isolate; | |
| 24 class Mutex; | |
| 25 class RawObject; | |
| 26 class SimulatorSetjmpBuffer; | |
| 27 class Thread; | |
| 28 | |
| 29 class Simulator { | |
| 30 public: | |
| 31 static const uword kSimulatorStackUnderflowSize = 64; | |
| 32 | |
| 33 Simulator(); | |
| 34 ~Simulator(); | |
| 35 | |
| 36 // The currently executing Simulator instance, which is associated to the | |
| 37 // current isolate | |
| 38 static Simulator* Current(); | |
| 39 | |
| 40 // Accessors for register state. | |
| 41 void set_register(Register reg, int32_t value); | |
| 42 int32_t get_register(Register reg) const; | |
| 43 | |
| 44 // Accessors for floating point register state. | |
| 45 void set_fregister(FRegister freg, int32_t value); | |
| 46 void set_fregister_float(FRegister freg, float value); | |
| 47 void set_fregister_double(FRegister freg, double value); | |
| 48 void set_fregister_long(FRegister freg, int64_t value); | |
| 49 | |
| 50 int32_t get_fregister(FRegister freg) const; | |
| 51 float get_fregister_float(FRegister freg) const; | |
| 52 double get_fregister_double(FRegister freg) const; | |
| 53 int64_t get_fregister_long(FRegister freg) const; | |
| 54 | |
| 55 void set_dregister_bits(DRegister freg, int64_t value); | |
| 56 void set_dregister(DRegister freg, double value); | |
| 57 | |
| 58 int64_t get_dregister_bits(DRegister freg) const; | |
| 59 double get_dregister(DRegister freg) const; | |
| 60 | |
| 61 int32_t get_sp() const { return get_register(SPREG); } | |
| 62 | |
| 63 // Accessor for the pc. | |
| 64 void set_pc(int32_t value) { pc_ = value; } | |
| 65 int32_t get_pc() const { return pc_; } | |
| 66 | |
| 67 // Accessors for hi, lo registers. | |
| 68 void set_hi_register(int32_t value) { hi_reg_ = value; } | |
| 69 void set_lo_register(int32_t value) { lo_reg_ = value; } | |
| 70 int32_t get_hi_register() const { return hi_reg_; } | |
| 71 int32_t get_lo_register() const { return lo_reg_; } | |
| 72 | |
| 73 int32_t get_fcsr_condition_bit(int32_t cc) const { | |
| 74 if (cc == 0) { | |
| 75 return 23; | |
| 76 } else { | |
| 77 return 24 + cc; | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 void set_fcsr_bit(uint32_t cc, bool value) { | |
| 82 if (value) { | |
| 83 fcsr_ |= (1 << cc); | |
| 84 } else { | |
| 85 fcsr_ &= ~(1 << cc); | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 bool test_fcsr_bit(uint32_t cc) { return fcsr_ & (1 << cc); } | |
| 90 | |
| 91 // Accessors to the internal simulator stack base and top. | |
| 92 uword StackBase() const { return reinterpret_cast<uword>(stack_); } | |
| 93 uword StackTop() const; | |
| 94 | |
| 95 // Accessor to the instruction counter. | |
| 96 uint64_t get_icount() const { return icount_; } | |
| 97 | |
| 98 // The thread's top_exit_frame_info refers to a Dart frame in the simulator | |
| 99 // stack. The simulator's top_exit_frame_info refers to a C++ frame in the | |
| 100 // native stack. | |
| 101 uword top_exit_frame_info() const { return top_exit_frame_info_; } | |
| 102 void set_top_exit_frame_info(uword value) { top_exit_frame_info_ = value; } | |
| 103 | |
| 104 // Call on program start. | |
| 105 static void InitOnce(); | |
| 106 | |
| 107 // Dart generally calls into generated code with 4 parameters. This is a | |
| 108 // convenience function, which sets up the simulator state and grabs the | |
| 109 // result on return. When fp_return is true the return value is the D0 | |
| 110 // floating point register. Otherwise, the return value is V1:V0. | |
| 111 int64_t Call(int32_t entry, | |
| 112 int32_t parameter0, | |
| 113 int32_t parameter1, | |
| 114 int32_t parameter2, | |
| 115 int32_t parameter3, | |
| 116 bool fp_return = false, | |
| 117 bool fp_args = false); | |
| 118 | |
| 119 // Implementation of atomic compare and exchange in the same synchronization | |
| 120 // domain as other synchronization primitive instructions (e.g. ldrex, strex). | |
| 121 static uword CompareExchange(uword* address, | |
| 122 uword compare_value, | |
| 123 uword new_value); | |
| 124 static uint32_t CompareExchangeUint32(uint32_t* address, | |
| 125 uint32_t compare_value, | |
| 126 uint32_t new_value); | |
| 127 | |
| 128 // Runtime and native call support. | |
| 129 enum CallKind { | |
| 130 kRuntimeCall, | |
| 131 kLeafRuntimeCall, | |
| 132 kLeafFloatRuntimeCall, | |
| 133 kBootstrapNativeCall, | |
| 134 kNativeCall | |
| 135 }; | |
| 136 static uword RedirectExternalReference(uword function, | |
| 137 CallKind call_kind, | |
| 138 int argument_count); | |
| 139 | |
| 140 static uword FunctionForRedirect(uword redirect); | |
| 141 | |
| 142 void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread); | |
| 143 | |
| 144 private: | |
| 145 // A pc value used to signal the simulator to stop execution. Generally | |
| 146 // the ra is set to this value on transition from native C code to | |
| 147 // simulated execution, so that the simulator can "return" to the native | |
| 148 // C code. | |
| 149 static const uword kEndSimulatingPC = -1; | |
| 150 | |
| 151 // Special registers for the results of div, divu. | |
| 152 int32_t hi_reg_; | |
| 153 int32_t lo_reg_; | |
| 154 | |
| 155 int32_t registers_[kNumberOfCpuRegisters]; | |
| 156 int32_t fregisters_[kNumberOfFRegisters]; | |
| 157 int32_t fcsr_; | |
| 158 uword pc_; | |
| 159 | |
| 160 // Simulator support. | |
| 161 char* stack_; | |
| 162 uint64_t icount_; | |
| 163 bool delay_slot_; | |
| 164 SimulatorSetjmpBuffer* last_setjmp_buffer_; | |
| 165 uword top_exit_frame_info_; | |
| 166 | |
| 167 // Registered breakpoints. | |
| 168 Instr* break_pc_; | |
| 169 int32_t break_instr_; | |
| 170 | |
| 171 // Illegal memory access support. | |
| 172 static bool IsIllegalAddress(uword addr) { return addr < 64 * 1024; } | |
| 173 void HandleIllegalAccess(uword addr, Instr* instr); | |
| 174 | |
| 175 // Read and write memory. | |
| 176 void UnalignedAccess(const char* msg, uword addr, Instr* instr); | |
| 177 | |
| 178 // Handles a legal instruction that the simulator does not implement. | |
| 179 void UnimplementedInstruction(Instr* instr); | |
| 180 | |
| 181 void set_pc(uword value) { pc_ = value; } | |
| 182 | |
| 183 void Format(Instr* instr, const char* format); | |
| 184 | |
| 185 inline int8_t ReadB(uword addr); | |
| 186 inline uint8_t ReadBU(uword addr); | |
| 187 inline int16_t ReadH(uword addr, Instr* instr); | |
| 188 inline uint16_t ReadHU(uword addr, Instr* instr); | |
| 189 inline intptr_t ReadW(uword addr, Instr* instr); | |
| 190 | |
| 191 inline void WriteB(uword addr, uint8_t value); | |
| 192 inline void WriteH(uword addr, uint16_t value, Instr* isntr); | |
| 193 inline void WriteW(uword addr, intptr_t value, Instr* instr); | |
| 194 | |
| 195 inline double ReadD(uword addr, Instr* instr); | |
| 196 inline void WriteD(uword addr, double value, Instr* instr); | |
| 197 | |
| 198 // We keep track of 16 exclusive access address tags across all threads. | |
| 199 // Since we cannot simulate a native context switch, which clears | |
| 200 // the exclusive access state of the local monitor, we associate the thread | |
| 201 // requesting exclusive access to the address tag. | |
| 202 // Multiple threads requesting exclusive access (using the LL instruction) | |
| 203 // to the same address will result in multiple address tags being created for | |
| 204 // the same address, one per thread. | |
| 205 // At any given time, each thread is associated to at most one address tag. | |
| 206 static Mutex* exclusive_access_lock_; | |
| 207 static const int kNumAddressTags = 16; | |
| 208 static struct AddressTag { | |
| 209 Thread* thread; | |
| 210 uword addr; | |
| 211 } exclusive_access_state_[kNumAddressTags]; | |
| 212 static int next_address_tag_; | |
| 213 | |
| 214 // Synchronization primitives support. | |
| 215 void ClearExclusive(); | |
| 216 intptr_t ReadExclusiveW(uword addr, Instr* instr); | |
| 217 intptr_t WriteExclusiveW(uword addr, intptr_t value, Instr* instr); | |
| 218 | |
| 219 // Set access to given address to 'exclusive state' for current thread. | |
| 220 static void SetExclusiveAccess(uword addr); | |
| 221 | |
| 222 // Returns true if the current thread has exclusive access to given address, | |
| 223 // returns false otherwise. In either case, set access to given address to | |
| 224 // 'open state' for all threads. | |
| 225 // If given addr is NULL, set access to 'open state' for current | |
| 226 // thread (CLREX). | |
| 227 static bool HasExclusiveAccessAndOpen(uword addr); | |
| 228 | |
| 229 void DoBranch(Instr* instr, bool taken, bool likely); | |
| 230 void DoBreak(Instr* instr); | |
| 231 | |
| 232 void DecodeSpecial(Instr* instr); | |
| 233 void DecodeSpecial2(Instr* instr); | |
| 234 void DecodeRegImm(Instr* instr); | |
| 235 void DecodeCop1(Instr* instr); | |
| 236 void InstructionDecode(Instr* instr); | |
| 237 | |
| 238 void Execute(); | |
| 239 void ExecuteDelaySlot(); | |
| 240 | |
| 241 // Returns true if tracing of executed instructions is enabled. | |
| 242 bool IsTracingExecution() const; | |
| 243 | |
| 244 // Longjmp support for exceptions. | |
| 245 SimulatorSetjmpBuffer* last_setjmp_buffer() { return last_setjmp_buffer_; } | |
| 246 void set_last_setjmp_buffer(SimulatorSetjmpBuffer* buffer) { | |
| 247 last_setjmp_buffer_ = buffer; | |
| 248 } | |
| 249 | |
| 250 friend class SimulatorDebugger; | |
| 251 friend class SimulatorSetjmpBuffer; | |
| 252 DISALLOW_COPY_AND_ASSIGN(Simulator); | |
| 253 }; | |
| 254 | |
| 255 } // namespace dart | |
| 256 | |
| 257 #endif // RUNTIME_VM_SIMULATOR_MIPS_H_ | |
| OLD | NEW |