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