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