07ee86a5a2
The calling conventions on AIX uses function descriptors,
which means that pointers to functions do not point to code,
but instead point to metadata about them. When calling JITed code,
we must assure to use function descriptors instead of raw pointers when
needed. Before this CL 213504b
, all CallCFunction on AIX were guaranteed to have
function descriptors. Starting form the CL mentioned above, CallCFunction can also
Jump to a Trampoline which does not have a function descriptor, hence a new
"CallCFunctionWithoutFunctionDescriptor" method is proposed to deal with this issue.
BUG= v8:9766
Change-Id: I9343c31c812f5d4dda8503a5adf024b24dbde072
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1825961
Commit-Queue: Milad Farazmand <miladfar@ca.ibm.com>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64357}
170 lines
5.9 KiB
C++
170 lines
5.9 KiB
C++
// 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)
|
|
FATAL("Generated code execution not possible during cross-compilation.");
|
|
#endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN)
|
|
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.
|
|
#if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN)
|
|
FATAL("Generated code execution not possible during cross-compilation.");
|
|
#endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN)
|
|
#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
|
|
}
|
|
#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_
|