• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_SIMULATOR_BASE_H_
6 #define V8_SIMULATOR_BASE_H_
7 
8 #include <type_traits>
9 
10 #include "src/globals.h"
11 #include "src/isolate.h"
12 
13 #if defined(USE_SIMULATOR)
14 
15 namespace v8 {
16 namespace internal {
17 
18 class Instruction;
19 class Redirection;
20 
21 class SimulatorBase {
22  public:
23   // Call on process start and exit.
24   static void InitializeOncePerProcess();
25   static void GlobalTearDown();
26 
redirection_mutex()27   static base::Mutex* redirection_mutex() { return redirection_mutex_; }
redirection()28   static Redirection* redirection() { return redirection_; }
set_redirection(Redirection * r)29   static void set_redirection(Redirection* r) { redirection_ = r; }
30 
i_cache_mutex()31   static base::Mutex* i_cache_mutex() { return i_cache_mutex_; }
i_cache()32   static base::CustomMatcherHashMap* i_cache() { return i_cache_; }
33 
34   // Runtime call support.
35   static Address RedirectExternalReference(Address external_function,
36                                            ExternalReference::Type type);
37 
38  protected:
39   template <typename Return, typename SimT, typename CallImpl, typename... Args>
VariadicCall(SimT * sim,CallImpl call,Address entry,Args...args)40   static Return VariadicCall(SimT* sim, CallImpl call, Address entry,
41                              Args... args) {
42     // Convert all arguments to intptr_t. Fails if any argument is not integral
43     // or pointer.
44     std::array<intptr_t, sizeof...(args)> args_arr{{ConvertArg(args)...}};
45     intptr_t ret = (sim->*call)(entry, args_arr.size(), args_arr.data());
46     return ConvertReturn<Return>(ret);
47   }
48 
49   // Convert back integral return types. This is always a narrowing conversion.
50   template <typename T>
51   static typename std::enable_if<std::is_integral<T>::value, T>::type
ConvertReturn(intptr_t ret)52   ConvertReturn(intptr_t ret) {
53     static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize");
54     return static_cast<T>(ret);
55   }
56 
57   // Convert back pointer-typed return types.
58   template <typename T>
59   static typename std::enable_if<std::is_pointer<T>::value, T>::type
ConvertReturn(intptr_t ret)60   ConvertReturn(intptr_t ret) {
61     return reinterpret_cast<T>(ret);
62   }
63 
64   // Convert back void return type (i.e. no return).
65   template <typename T>
ConvertReturn(intptr_t ret)66   static typename std::enable_if<std::is_void<T>::value, T>::type ConvertReturn(
67       intptr_t ret) {}
68 
69  private:
70   static base::Mutex* redirection_mutex_;
71   static Redirection* redirection_;
72 
73   static base::Mutex* i_cache_mutex_;
74   static base::CustomMatcherHashMap* i_cache_;
75 
76   // Helper methods to convert arbitrary integer or pointer arguments to the
77   // needed generic argument type intptr_t.
78 
79   // Convert integral argument to intptr_t.
80   template <typename T>
81   static typename std::enable_if<std::is_integral<T>::value, intptr_t>::type
ConvertArg(T arg)82   ConvertArg(T arg) {
83     static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize");
84 #if V8_TARGET_ARCH_MIPS64
85     // The MIPS64 calling convention is to sign extend all values, even unsigned
86     // ones.
87     using signed_t = typename std::make_signed<T>::type;
88     return static_cast<intptr_t>(static_cast<signed_t>(arg));
89 #else
90     // Standard C++ convertion: Sign-extend signed values, zero-extend unsigned
91     // values.
92     return static_cast<intptr_t>(arg);
93 #endif
94   }
95 
96   // Convert pointer-typed argument to intptr_t.
97   template <typename T>
98   static typename std::enable_if<std::is_pointer<T>::value, intptr_t>::type
ConvertArg(T arg)99   ConvertArg(T arg) {
100     return reinterpret_cast<intptr_t>(arg);
101   }
102 };
103 
104 // When the generated code calls an external reference we need to catch that in
105 // the simulator.  The external reference will be a function compiled for the
106 // host architecture.  We need to call that function instead of trying to
107 // execute it with the simulator.  We do that by redirecting the external
108 // reference to a trapping instruction that is handled by the simulator.  We
109 // write the original destination of the jump just at a known offset from the
110 // trapping instruction so the simulator knows what to call.
111 //
112 // The following are trapping instructions used for various architectures:
113 //  - V8_TARGET_ARCH_ARM: svc (Supervisor Call)
114 //  - V8_TARGET_ARCH_ARM64: svc (Supervisor Call)
115 //  - V8_TARGET_ARCH_MIPS: swi (software-interrupt)
116 //  - V8_TARGET_ARCH_MIPS64: swi (software-interrupt)
117 //  - V8_TARGET_ARCH_PPC: svc (Supervisor Call)
118 //  - V8_TARGET_ARCH_S390: svc (Supervisor Call)
119 class Redirection {
120  public:
121   Redirection(Address external_function, ExternalReference::Type type);
122 
address_of_instruction()123   Address address_of_instruction() {
124 #if ABI_USES_FUNCTION_DESCRIPTORS
125     return reinterpret_cast<Address>(function_descriptor_);
126 #else
127     return reinterpret_cast<Address>(&instruction_);
128 #endif
129   }
130 
external_function()131   void* external_function() {
132     return reinterpret_cast<void*>(external_function_);
133   }
type()134   ExternalReference::Type type() { return type_; }
135 
136   static Redirection* Get(Address external_function,
137                           ExternalReference::Type type);
138 
FromInstruction(Instruction * instruction)139   static Redirection* FromInstruction(Instruction* instruction) {
140     Address addr_of_instruction = reinterpret_cast<Address>(instruction);
141     Address addr_of_redirection =
142         addr_of_instruction - offsetof(Redirection, instruction_);
143     return reinterpret_cast<Redirection*>(addr_of_redirection);
144   }
145 
ReverseRedirection(intptr_t reg)146   static void* ReverseRedirection(intptr_t reg) {
147     Redirection* redirection = FromInstruction(
148         reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
149     return redirection->external_function();
150   }
151 
DeleteChain(Redirection * redirection)152   static void DeleteChain(Redirection* redirection) {
153     while (redirection != nullptr) {
154       Redirection* next = redirection->next_;
155       delete redirection;
156       redirection = next;
157     }
158   }
159 
160  private:
161   Address external_function_;
162   uint32_t instruction_;
163   ExternalReference::Type type_;
164   Redirection* next_;
165 #if ABI_USES_FUNCTION_DESCRIPTORS
166   intptr_t function_descriptor_[3];
167 #endif
168 };
169 
170 }  // namespace internal
171 }  // namespace v8
172 
173 #endif  // defined(USE_SIMULATOR)
174 #endif  // V8_SIMULATOR_BASE_H_
175