-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
Expand file tree
/
Copy pathsimulator.h
More file actions
248 lines (214 loc) Β· 8.64 KB
/
simulator.h
File metadata and controls
248 lines (214 loc) Β· 8.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
// Copyright 2009 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_EXECUTION_SIMULATOR_H_
#define V8_EXECUTION_SIMULATOR_H_
#include "src/common/globals.h"
#include "src/objects/code.h"
#if !defined(USE_SIMULATOR)
#include "src/base/platform/platform.h"
#include "src/execution/isolate.h"
#include "src/utils/utils.h"
#endif
#if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
// No simulator for ia32 or x64.
#elif V8_TARGET_ARCH_ARM64
#include "src/execution/arm64/simulator-arm64.h"
#elif V8_TARGET_ARCH_ARM
#include "src/execution/arm/simulator-arm.h"
#elif V8_TARGET_ARCH_PPC64
#include "src/execution/ppc/simulator-ppc.h"
#elif V8_TARGET_ARCH_MIPS64
#include "src/execution/mips64/simulator-mips64.h"
#elif V8_TARGET_ARCH_LOONG64
#include "src/execution/loong64/simulator-loong64.h"
#elif V8_TARGET_ARCH_S390X
#include "src/execution/s390/simulator-s390.h"
#elif V8_TARGET_ARCH_RISCV32 || V8_TARGET_ARCH_RISCV64
#include "src/execution/riscv/simulator-riscv.h"
#else
#error Unsupported target architecture.
#endif
namespace heap::base {
class StackVisitor;
}
namespace v8 {
namespace internal {
#if defined(USE_SIMULATOR)
// Running with a simulator.
// The simulator has its own stack. Thus it has a different stack limit from
// the C-based native code. The JS-based limit normally points near the end of
// the simulator stack. When the C-based limit is exhausted we reflect that by
// lowering the JS-based limit as well, to make stack checks trigger.
class SimulatorStack : public v8::internal::AllStatic {
public:
static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
uintptr_t c_limit) {
return Simulator::current(isolate)->StackLimit(c_limit);
}
#if V8_ENABLE_WEBASSEMBLY
// Includes the safety stack limit gap.
static inline base::Vector<uint8_t> GetCentralStackView(
v8::internal::Isolate* isolate) {
return Simulator::current(isolate)->GetCentralStackView();
}
// Size of the safety stack limit gap.
static int JSStackLimitMargin() { return Simulator::JSStackLimitMargin(); }
#endif
// Iterates the simulator registers and stack for conservative stack scanning.
static void IterateRegistersAndStack(Isolate* isolate,
::heap::base::StackVisitor* visitor) {
DCHECK_NOT_NULL(isolate);
Simulator::current(isolate)->IterateRegistersAndStack(visitor);
}
// When running on the simulator, we should leave the C stack limits alone
// when switching stacks for Wasm.
static inline bool ShouldSwitchCStackForWasmStackSwitching() { return false; }
// Returns the current stack address on the simulator stack frame.
// The returned address is comparable with JS stack address.
static inline uintptr_t RegisterJSStackComparableAddress(
v8::internal::Isolate* isolate) {
// The value of |kPlaceHolder| is actually not used. It just occupies a
// single word on the stack frame of the simulator.
const uintptr_t kPlaceHolder = 0x4A535350u; // "JSSP" in ASCII
return Simulator::current(isolate)->PushAddress(kPlaceHolder);
}
static inline void UnregisterJSStackComparableAddress(
v8::internal::Isolate* isolate) {
Simulator::current(isolate)->PopAddress();
}
};
#else // defined(USE_SIMULATOR)
// Running without a simulator on a native platform.
// The stack limit beyond which we will throw stack overflow errors in
// generated code. Because generated code uses the C stack, we just use
// the C stack limit.
class SimulatorStack : public v8::internal::AllStatic {
public:
static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
uintptr_t c_limit) {
USE(isolate);
return c_limit;
}
#if V8_ENABLE_WEBASSEMBLY
static inline base::Vector<uint8_t> GetCentralStackView(
v8::internal::Isolate* isolate) {
uintptr_t upper_bound = base::Stack::GetStackStart();
size_t size = isolate->stack_size() + JSStackLimitMargin();
uintptr_t lower_bound = upper_bound - size;
return base::VectorOf(reinterpret_cast<uint8_t*>(lower_bound), size);
}
static int JSStackLimitMargin() {
return wasm::StackMemory::JSCentralStackLimitMarginKB() * KB;
}
#endif
static void IterateRegistersAndStack(Isolate* isolate,
::heap::base::StackVisitor* visitor) {}
// When running on real hardware, we should also switch the C stack limit
// when switching stacks for Wasm.
static inline bool ShouldSwitchCStackForWasmStackSwitching() { return true; }
// Returns the current stack address on the native stack frame.
// The returned address is comparable with JS stack address.
static inline uintptr_t RegisterJSStackComparableAddress(
v8::internal::Isolate* isolate) {
USE(isolate);
return internal::GetCurrentStackPosition();
}
static inline void UnregisterJSStackComparableAddress(
v8::internal::Isolate* isolate) {
USE(isolate);
}
};
#endif // defined(USE_SIMULATOR)
// Use this class either as {GeneratedCode<ret, arg1, arg2>} or
// {GeneratedCode<ret(arg1, arg2)>} (see specialization below).
template <typename Return, typename... Args>
class GeneratedCode {
public:
using Signature = Return(Args...);
static GeneratedCode FromAddress(Isolate* isolate, Address addr) {
return GeneratedCode(isolate, reinterpret_cast<Signature*>(addr));
}
static GeneratedCode FromBuffer(Isolate* isolate, uint8_t* buffer) {
return GeneratedCode(isolate, reinterpret_cast<Signature*>(buffer));
}
static GeneratedCode FromCode(Isolate* isolate, Tagged<Code> code) {
return FromAddress(isolate, code->instruction_start());
}
#ifdef USE_SIMULATOR
// Defined in simulator-base.h.
Return Call(Args... args) {
// Starboard is a platform abstraction interface that also include Windows
// platforms like UWP.
#if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) && \
!defined(V8_OS_STARBOARD) && !defined(V8_TARGET_ARCH_ARM)
FATAL(
"Generated code execution not possible during cross-compilation."
"Also, generic C function calls are not implemented on 32-bit arm "
"yet.");
#endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) &&
// !defined(V8_OS_STARBOARD) && !defined(V8_TARGET_ARCH_ARM)
return Simulator::current(isolate_)->template Call<Return>(
reinterpret_cast<Address>(fn_ptr_), args...);
}
#else
DISABLE_CFI_ICALL Return Call(Args... args) {
// When running without a simulator we call the entry directly.
// Starboard is a platform abstraction interface that also include Windows
// platforms like UWP.
#if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) && \
!defined(V8_OS_STARBOARD)
FATAL("Generated code execution not possible during cross-compilation.");
#endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN)
#if ABI_USES_FUNCTION_DESCRIPTORS
#if V8_OS_ZOS
// z/OS ABI requires function descriptors (FD). Artificially create a pseudo
// FD to ensure correct dispatch to generated code.
void* function_desc[2] = {0, reinterpret_cast<void*>(fn_ptr_)};
asm volatile(" stg 5,%0 " : "=m"(function_desc[0])::"r5");
Signature* fn = reinterpret_cast<Signature*>(function_desc);
return fn(args...);
#else
// AIX ABI requires function descriptors (FD). Artificially create a pseudo
// FD to ensure correct dispatch to generated code.
void* function_desc[3];
Signature* fn;
asm("std %1, 0(%2)\n\t"
"li 0, 0\n\t"
"std 0, 8(%2)\n\t"
"std 0, 16(%2)\n\t"
"mr %0, %2\n\t"
: "=r"(fn)
: "r"(fn_ptr_), "r"(function_desc)
: "memory", "0");
return fn(args...);
#endif // V8_OS_ZOS
#else
return fn_ptr_(args...);
#endif // ABI_USES_FUNCTION_DESCRIPTORS
}
#endif // USE_SIMULATOR
DISABLE_CFI_ICALL Return CallSandboxed(Args... args) {
EnterSandboxScope sandboxed;
return Call(args...);
}
private:
friend class GeneratedCode<Return(Args...)>;
Isolate* isolate_;
Signature* fn_ptr_;
GeneratedCode(Isolate* isolate, Signature* fn_ptr)
: isolate_(isolate), fn_ptr_(fn_ptr) {}
};
// Allow to use {GeneratedCode<ret(arg1, arg2)>} instead of
// {GeneratedCode<ret, arg1, arg2>}.
template <typename Return, typename... Args>
class GeneratedCode<Return(Args...)> : public GeneratedCode<Return, Args...> {
public:
// Automatically convert from {GeneratedCode<ret, arg1, arg2>} to
// {GeneratedCode<ret(arg1, arg2)>}.
GeneratedCode(GeneratedCode<Return, Args...> other)
: GeneratedCode<Return, Args...>(other.isolate_, other.fn_ptr_) {}
};
} // namespace internal
} // namespace v8
#endif // V8_EXECUTION_SIMULATOR_H_