#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
#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)
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
static inline base::Vector<uint8_t> GetCentralStackView(
v8::internal::Isolate* isolate) {
return Simulator::current(isolate)->GetCentralStackView();
}
static int JSStackLimitMargin() { return Simulator::JSStackLimitMargin(); }
#endif
static void IterateRegistersAndStack(Isolate* isolate,
::heap::base::StackVisitor* visitor) {
DCHECK_NOT_NULL(isolate);
Simulator::current(isolate)->IterateRegistersAndStack(visitor);
}
static inline bool ShouldSwitchCStackForWasmStackSwitching() { return false; }
static inline uintptr_t RegisterJSStackComparableAddress(
v8::internal::Isolate* isolate) {
const uintptr_t kPlaceHolder = 0x4A535350u;
return Simulator::current(isolate)->PushAddress(kPlaceHolder);
}
static inline void UnregisterJSStackComparableAddress(
v8::internal::Isolate* isolate) {
Simulator::current(isolate)->PopAddress();
}
};
#else
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) {}
static inline bool ShouldSwitchCStackForWasmStackSwitching() { return true; }
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
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
Return Call(Args... args) {
#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
return Simulator::current(isolate_)->template Call<Return>(
reinterpret_cast<Address>(fn_ptr_), args...);
}
#else
DISABLE_CFI_ICALL Return Call(Args... args) {
#if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) && \
!defined(V8_OS_STARBOARD)
FATAL("Generated code execution not possible during cross-compilation.");
#endif
#if ABI_USES_FUNCTION_DESCRIPTORS
#if V8_OS_ZOS
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
volatile Address function_desc[] = {reinterpret_cast<Address>(fn_ptr_), 0,
0};
Signature* fn = reinterpret_cast<Signature*>(function_desc);
return fn(args...);
#endif
#else
return fn_ptr_(args...);
#endif
}
#endif
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) {}
};
template <typename Return, typename... Args>
class GeneratedCode<Return(Args...)> : public GeneratedCode<Return, Args...> {
public:
GeneratedCode(GeneratedCode<Return, Args...> other)
: GeneratedCode<Return, Args...>(other.isolate_, other.fn_ptr_) {}
};
}
}
#endif