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