| // Copyright 2017 the V8 project authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef V8_SIMULATOR_BASE_H_ | |
| #define V8_SIMULATOR_BASE_H_ | |
| #include <type_traits> | |
| #include "src/globals.h" | |
| #include "src/isolate.h" | |
| #if defined(USE_SIMULATOR) | |
| namespace v8 { | |
| namespace internal { | |
| class Instruction; | |
| class Redirection; | |
| class SimulatorBase { | |
| public: | |
| // Call on process start and exit. | |
| static void InitializeOncePerProcess(); | |
| static void GlobalTearDown(); | |
| static base::Mutex* redirection_mutex() { return redirection_mutex_; } | |
| static Redirection* redirection() { return redirection_; } | |
| static void set_redirection(Redirection* r) { redirection_ = r; } | |
| static base::Mutex* i_cache_mutex() { return i_cache_mutex_; } | |
| static base::CustomMatcherHashMap* i_cache() { return i_cache_; } | |
| // Runtime call support. | |
| static Address RedirectExternalReference(Address external_function, | |
| ExternalReference::Type type); | |
| protected: | |
| template <typename Return, typename SimT, typename CallImpl, typename... Args> | |
| static Return VariadicCall(SimT* sim, CallImpl call, Address entry, | |
| Args... args) { | |
| // Convert all arguments to intptr_t. Fails if any argument is not integral | |
| // or pointer. | |
| std::array<intptr_t, sizeof...(args)> args_arr{{ConvertArg(args)...}}; | |
| intptr_t ret = (sim->*call)(entry, args_arr.size(), args_arr.data()); | |
| return ConvertReturn<Return>(ret); | |
| } | |
| // Convert back integral return types. This is always a narrowing conversion. | |
| template <typename T> | |
| static typename std::enable_if<std::is_integral<T>::value, T>::type | |
| ConvertReturn(intptr_t ret) { | |
| static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize"); | |
| return static_cast<T>(ret); | |
| } | |
| // Convert back pointer-typed return types. | |
| template <typename T> | |
| static typename std::enable_if<std::is_pointer<T>::value, T>::type | |
| ConvertReturn(intptr_t ret) { | |
| return reinterpret_cast<T>(ret); | |
| } | |
| // Convert back void return type (i.e. no return). | |
| template <typename T> | |
| static typename std::enable_if<std::is_void<T>::value, T>::type ConvertReturn( | |
| intptr_t ret) {} | |
| private: | |
| static base::Mutex* redirection_mutex_; | |
| static Redirection* redirection_; | |
| static base::Mutex* i_cache_mutex_; | |
| static base::CustomMatcherHashMap* i_cache_; | |
| // Helper methods to convert arbitrary integer or pointer arguments to the | |
| // needed generic argument type intptr_t. | |
| // Convert integral argument to intptr_t. | |
| template <typename T> | |
| static typename std::enable_if<std::is_integral<T>::value, intptr_t>::type | |
| ConvertArg(T arg) { | |
| static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize"); | |
| #if V8_TARGET_ARCH_MIPS64 | |
| // The MIPS64 calling convention is to sign extend all values, even unsigned | |
| // ones. | |
| using signed_t = typename std::make_signed<T>::type; | |
| return static_cast<intptr_t>(static_cast<signed_t>(arg)); | |
| #else | |
| // Standard C++ convertion: Sign-extend signed values, zero-extend unsigned | |
| // values. | |
| return static_cast<intptr_t>(arg); | |
| #endif | |
| } | |
| // Convert pointer-typed argument to intptr_t. | |
| template <typename T> | |
| static typename std::enable_if<std::is_pointer<T>::value, intptr_t>::type | |
| ConvertArg(T arg) { | |
| return reinterpret_cast<intptr_t>(arg); | |
| } | |
| }; | |
| // When the generated code calls an external reference we need to catch that in | |
| // the simulator. The external reference will be a function compiled for the | |
| // host architecture. We need to call that function instead of trying to | |
| // execute it with the simulator. We do that by redirecting the external | |
| // reference to a trapping instruction that is handled by the simulator. We | |
| // write the original destination of the jump just at a known offset from the | |
| // trapping instruction so the simulator knows what to call. | |
| // | |
| // The following are trapping instructions used for various architectures: | |
| // - V8_TARGET_ARCH_ARM: svc (Supervisor Call) | |
| // - V8_TARGET_ARCH_ARM64: svc (Supervisor Call) | |
| // - V8_TARGET_ARCH_MIPS: swi (software-interrupt) | |
| // - V8_TARGET_ARCH_MIPS64: swi (software-interrupt) | |
| // - V8_TARGET_ARCH_PPC: svc (Supervisor Call) | |
| // - V8_TARGET_ARCH_S390: svc (Supervisor Call) | |
| class Redirection { | |
| public: | |
| Redirection(Address external_function, ExternalReference::Type type); | |
| Address address_of_instruction() { | |
| #if ABI_USES_FUNCTION_DESCRIPTORS | |
| return reinterpret_cast<Address>(function_descriptor_); | |
| #else | |
| return reinterpret_cast<Address>(&instruction_); | |
| #endif | |
| } | |
| void* external_function() { | |
| return reinterpret_cast<void*>(external_function_); | |
| } | |
| ExternalReference::Type type() { return type_; } | |
| static Redirection* Get(Address external_function, | |
| ExternalReference::Type type); | |
| static Redirection* FromInstruction(Instruction* instruction) { | |
| Address addr_of_instruction = reinterpret_cast<Address>(instruction); | |
| Address addr_of_redirection = | |
| addr_of_instruction - offsetof(Redirection, instruction_); | |
| return reinterpret_cast<Redirection*>(addr_of_redirection); | |
| } | |
| static void* ReverseRedirection(intptr_t reg) { | |
| Redirection* redirection = FromInstruction( | |
| reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg))); | |
| return redirection->external_function(); | |
| } | |
| static void DeleteChain(Redirection* redirection) { | |
| while (redirection != nullptr) { | |
| Redirection* next = redirection->next_; | |
| delete redirection; | |
| redirection = next; | |
| } | |
| } | |
| private: | |
| Address external_function_; | |
| uint32_t instruction_; | |
| ExternalReference::Type type_; | |
| Redirection* next_; | |
| #if ABI_USES_FUNCTION_DESCRIPTORS | |
| intptr_t function_descriptor_[3]; | |
| #endif | |
| }; | |
| } // namespace internal | |
| } // namespace v8 | |
| #endif // defined(USE_SIMULATOR) | |
| #endif // V8_SIMULATOR_BASE_H_ |