blob: 81051fe847fc1edcc104d579630fb400ac242d43 [file] [log] [blame]
// 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/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_PPC
#include "src/execution/ppc/simulator-ppc.h"
#elif V8_TARGET_ARCH_MIPS
#include "src/execution/mips/simulator-mips.h"
#elif V8_TARGET_ARCH_MIPS64
#include "src/execution/mips64/simulator-mips64.h"
#elif V8_TARGET_ARCH_S390
#include "src/execution/s390/simulator-s390.h"
#else
#error Unsupported target architecture.
#endif
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);
}
// 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;
}
// 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, byte* buffer) {
return GeneratedCode(isolate, reinterpret_cast<Signature*>(buffer));
}
static GeneratedCode FromCode(Code code) {
return FromAddress(code.GetIsolate(), code.entry());
}
#ifdef USE_SIMULATOR
// Defined in simulator-base.h.
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
return Simulator::current(isolate_)->template Call<Return>(
reinterpret_cast<Address>(fn_ptr_), args...);
}
DISABLE_CFI_ICALL Return CallIrregexp(Args... args) { return Call(args...); }
#else
DISABLE_CFI_ICALL Return Call(Args... args) {
// When running without a simulator we call the entry directly.
#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 V8_OS_AIX
// AIX ABI requires function descriptors (FD). Artificially create a pseudo
// FD to ensure correct dispatch to generated code. The 'volatile'
// declaration is required to avoid the compiler from not observing the
// alias of the pseudo FD to the function pointer, and hence, optimizing the
// pseudo FD declaration/initialization away.
volatile Address function_desc[] = {reinterpret_cast<Address>(fn_ptr_), 0,
0};
Signature* fn = reinterpret_cast<Signature*>(function_desc);
return fn(args...);
#else
return fn_ptr_(args...);
#endif // V8_OS_AIX
}
DISABLE_CFI_ICALL Return CallIrregexp(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
// When running without a simulator we call the entry directly.
return fn_ptr_(args...);
}
#endif // USE_SIMULATOR
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_