| Index: runtime/vm/simulator_arm.h
|
| ===================================================================
|
| --- runtime/vm/simulator_arm.h (revision 0)
|
| +++ runtime/vm/simulator_arm.h (revision 0)
|
| @@ -0,0 +1,230 @@
|
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +// Declares a Simulator for ARM instructions if we are not generating a native
|
| +// ARM binary. This Simulator allows us to run and debug ARM code generation on
|
| +// regular desktop machines.
|
| +// Dart calls into generated code by "calling" the InvokeDartCode stub,
|
| +// which will start execution in the Simulator or forwards to the real entry
|
| +// on a ARM HW platform.
|
| +
|
| +#ifndef VM_SIMULATOR_ARM_H_
|
| +#define VM_SIMULATOR_ARM_H_
|
| +
|
| +#ifndef VM_SIMULATOR_H_
|
| +#error Do not include simulator_arm.h directly; use simulator.h.
|
| +#endif
|
| +
|
| +#include "vm/allocation.h"
|
| +#include "vm/constants_arm.h"
|
| +#include "vm/object.h"
|
| +
|
| +namespace dart {
|
| +
|
| +class Isolate;
|
| +class SimulatorSetjmpBuffer;
|
| +
|
| +class Simulator {
|
| + public:
|
| + static const size_t kSimulatorStackUnderflowSize = 64;
|
| +
|
| + Simulator();
|
| + ~Simulator();
|
| +
|
| + // The currently executing Simulator instance, which is associated to the
|
| + // current isolate
|
| + static Simulator* Current();
|
| +
|
| + // Accessors for register state. Reading the pc value adheres to the ARM
|
| + // architecture specification and is off by 8 from the currently executing
|
| + // instruction.
|
| + void set_register(Register reg, int32_t value);
|
| + int32_t get_register(Register reg) const;
|
| +
|
| + // Special case of set_register and get_register to access the raw PC value.
|
| + void set_pc(int32_t value);
|
| + int32_t get_pc() const;
|
| +
|
| + // Accessors for VFP register state.
|
| + void set_sregister(SRegister reg, float value);
|
| + float get_sregister(SRegister reg) const;
|
| + void set_dregister(DRegister reg, double value);
|
| + double get_dregister(DRegister reg) const;
|
| +
|
| + // Accessor to the internal simulator stack area.
|
| + uintptr_t StackTop() const;
|
| + uintptr_t StackLimit() const;
|
| +
|
| + // Executes ARM instructions until the PC reaches end_sim_pc.
|
| + void Execute();
|
| +
|
| + // Call on program start.
|
| + static void InitOnce();
|
| +
|
| + // Dart generally calls into generated code with 5 parameters. This is a
|
| + // convenience function, which sets up the simulator state and grabs the
|
| + // result on return.
|
| + int64_t Call(int32_t entry,
|
| + int32_t parameter0,
|
| + int32_t parameter1,
|
| + int32_t parameter2,
|
| + int32_t parameter3,
|
| + int32_t parameter4);
|
| +
|
| + // Implementation of atomic compare and exchange in the same synchronization
|
| + // domain as other synchronization primitive instructions (e.g. ldrex, strex).
|
| + static uword CompareExchange(uword* address,
|
| + uword compare_value,
|
| + uword new_value);
|
| +
|
| + // Runtime call support.
|
| + static uword RedirectExternalReference(void* function,
|
| + uint32_t argument_count);
|
| +
|
| + void Longjmp(int32_t pc, int32_t sp, int32_t fp, const Instance& object);
|
| +
|
| + private:
|
| + // Known bad pc value to ensure that the simulator does not execute
|
| + // without being properly setup.
|
| + static const uword kBadLR = -1;
|
| + // A pc value used to signal the simulator to stop execution. Generally
|
| + // the lr is set to this value on transition from native C code to
|
| + // simulated execution, so that the simulator can "return" to the native
|
| + // C code.
|
| + static const uword kEndSimulatingPC = -2;
|
| +
|
| + // CPU state.
|
| + int32_t registers_[kNumberOfCpuRegisters];
|
| + bool n_flag_;
|
| + bool z_flag_;
|
| + bool c_flag_;
|
| + bool v_flag_;
|
| +
|
| + // VFP state.
|
| + union { // S and D register banks are overlapping.
|
| + float sregisters_[kNumberOfSRegisters];
|
| + double dregisters_[kNumberOfDRegisters];
|
| + };
|
| + bool fp_n_flag_;
|
| + bool fp_z_flag_;
|
| + bool fp_c_flag_;
|
| + bool fp_v_flag_;
|
| +
|
| + // Simulator support.
|
| + char* stack_;
|
| + bool pc_modified_;
|
| + int icount_;
|
| + static bool flag_trace_sim_;
|
| + static int32_t flag_stop_sim_at_;
|
| + SimulatorSetjmpBuffer* last_setjmp_buffer_;
|
| +
|
| + // Registered breakpoints.
|
| + Instr* break_pc_;
|
| + int32_t break_instr_;
|
| +
|
| + // Illegal memory access support.
|
| + static bool IsIllegalAddress(uword addr) {
|
| + return addr < 64*1024;
|
| + }
|
| + void HandleIllegalAccess(uword addr, Instr* instr);
|
| +
|
| + // Unsupported instructions use Format to print an error and stop execution.
|
| + void Format(Instr* instr, const char* format);
|
| +
|
| + // Checks if the current instruction should be executed based on its
|
| + // condition bits.
|
| + bool ConditionallyExecute(Instr* instr);
|
| +
|
| + // Helper functions to set the conditional flags in the architecture state.
|
| + void SetNZFlags(int32_t val);
|
| + void SetCFlag(bool val);
|
| + void SetVFlag(bool val);
|
| + bool CarryFrom(int32_t left, int32_t right);
|
| + bool BorrowFrom(int32_t left, int32_t right);
|
| + bool OverflowFrom(int32_t alu_out,
|
| + int32_t left,
|
| + int32_t right,
|
| + bool addition);
|
| +
|
| + // Helper functions to decode common "addressing" modes.
|
| + int32_t GetShiftRm(Instr* instr, bool* carry_out);
|
| + int32_t GetImm(Instr* instr, bool* carry_out);
|
| + void HandleRList(Instr* instr, bool load);
|
| + void SupervisorCall(Instr* instr);
|
| +
|
| + // Read and write memory.
|
| + void UnalignedAccess(const char* msg, uword addr, Instr* instr);
|
| +
|
| + inline uint8_t ReadBU(uword addr);
|
| + inline int8_t ReadB(uword addr);
|
| + inline void WriteB(uword addr, uint8_t value);
|
| +
|
| + inline uint16_t ReadHU(uword addr, Instr* instr);
|
| + inline int16_t ReadH(uword addr, Instr* instr);
|
| + inline void WriteH(uword addr, uint16_t value, Instr* instr);
|
| +
|
| + inline int ReadW(uword addr, Instr* instr);
|
| + inline void WriteW(uword addr, int value, Instr* instr);
|
| +
|
| + // Synchronization primitives support.
|
| + void ClearExclusive();
|
| + int ReadExclusiveW(uword addr, Instr* instr);
|
| + int WriteExclusiveW(uword addr, int value, Instr* instr);
|
| +
|
| + // TODO(regis): Remove exclusive access support machinery if not needed.
|
| + // In Dart, there is at most one thread per isolate.
|
| + // We keep track of 16 exclusive access address tags across all isolates.
|
| + // Since we cannot simulate a native context switch, which clears
|
| + // the exclusive access state of the local monitor (using the CLREX
|
| + // instruction), we associate the isolate requesting exclusive access to the
|
| + // address tag. Multiple isolates requesting exclusive access (using the LDREX
|
| + // instruction) to the same address will result in multiple address tags being
|
| + // created for the same address, one per isolate.
|
| + // At any given time, each isolate is associated to at most one address tag.
|
| + static Mutex* exclusive_access_lock_;
|
| + static const int kNumAddressTags = 16;
|
| + static struct AddressTag {
|
| + Isolate* isolate;
|
| + uword addr;
|
| + } exclusive_access_state_[kNumAddressTags];
|
| + static int next_address_tag_;
|
| +
|
| + // Set access to given address to 'exclusive state' for current isolate.
|
| + static void SetExclusiveAccess(uword addr);
|
| +
|
| + // Returns true if the current isolate has exclusive access to given address,
|
| + // returns false otherwise. In either case, set access to given address to
|
| + // 'open state' for all isolates.
|
| + // If given addr is NULL, set access to 'open state' for current
|
| + // isolate (CLREX).
|
| + static bool HasExclusiveAccessAndOpen(uword addr);
|
| +
|
| + // Executing is handled based on the instruction type.
|
| + void DecodeType01(Instr* instr); // Both type 0 and type 1 rolled into one.
|
| + void DecodeType2(Instr* instr);
|
| + void DecodeType3(Instr* instr);
|
| + void DecodeType4(Instr* instr);
|
| + void DecodeType5(Instr* instr);
|
| + void DecodeType6(Instr* instr);
|
| + void DecodeType7(Instr* instr);
|
| +
|
| + // Executes one instruction.
|
| + void InstructionDecode(Instr* instr);
|
| +
|
| + // Longjmp support for exceptions.
|
| + SimulatorSetjmpBuffer* last_setjmp_buffer() {
|
| + return last_setjmp_buffer_;
|
| + }
|
| + void set_last_setjmp_buffer(SimulatorSetjmpBuffer* buffer) {
|
| + last_setjmp_buffer_ = buffer;
|
| + }
|
| +
|
| + friend class SimulatorDebugger;
|
| + friend class SimulatorSetjmpBuffer;
|
| + DISALLOW_COPY_AND_ASSIGN(Simulator);
|
| +};
|
| +
|
| +} // namespace dart
|
| +
|
| +#endif // VM_SIMULATOR_ARM_H_
|
|
|