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