056f927861
Tbr: ahaas@chromium.org,leszeks@chromium.org,verwaest@chromium.org Bug: v8:3770 Change-Id: Ia6530fbb70dac05e9972283781c3550d8b50e1eb Reviewed-on: https://chromium-review.googlesource.com/c/1390116 Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Alexei Filippov <alph@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#58470}
181 lines
5.9 KiB
C++
181 lines
5.9 KiB
C++
// Copyright 2017 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_SIMULATOR_BASE_H_
|
|
#define V8_SIMULATOR_BASE_H_
|
|
|
|
#include <type_traits>
|
|
|
|
#include "src/globals.h"
|
|
#include "src/isolate.h"
|
|
|
|
#if defined(USE_SIMULATOR)
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
class Instruction;
|
|
class Redirection;
|
|
|
|
class SimulatorBase {
|
|
public:
|
|
// Call on process start and exit.
|
|
static void InitializeOncePerProcess();
|
|
static void GlobalTearDown();
|
|
|
|
static base::Mutex* redirection_mutex() { return redirection_mutex_; }
|
|
static Redirection* redirection() { return redirection_; }
|
|
static void set_redirection(Redirection* r) { redirection_ = r; }
|
|
|
|
static base::Mutex* i_cache_mutex() { return i_cache_mutex_; }
|
|
static base::CustomMatcherHashMap* i_cache() { return i_cache_; }
|
|
|
|
// Runtime call support.
|
|
static Address RedirectExternalReference(Address external_function,
|
|
ExternalReference::Type type);
|
|
|
|
protected:
|
|
template <typename Return, typename SimT, typename CallImpl, typename... Args>
|
|
static Return VariadicCall(SimT* sim, CallImpl call, Address entry,
|
|
Args... args) {
|
|
// Convert all arguments to intptr_t. Fails if any argument is not integral
|
|
// or pointer.
|
|
std::array<intptr_t, sizeof...(args)> args_arr{{ConvertArg(args)...}};
|
|
intptr_t ret = (sim->*call)(entry, args_arr.size(), args_arr.data());
|
|
return ConvertReturn<Return>(ret);
|
|
}
|
|
|
|
// Convert back integral return types. This is always a narrowing conversion.
|
|
template <typename T>
|
|
static typename std::enable_if<std::is_integral<T>::value, T>::type
|
|
ConvertReturn(intptr_t ret) {
|
|
static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize");
|
|
return static_cast<T>(ret);
|
|
}
|
|
|
|
// Convert back pointer-typed return types.
|
|
template <typename T>
|
|
static typename std::enable_if<std::is_pointer<T>::value, T>::type
|
|
ConvertReturn(intptr_t ret) {
|
|
return reinterpret_cast<T>(ret);
|
|
}
|
|
|
|
template <typename T>
|
|
static typename std::enable_if<std::is_base_of<Object, T>::value, T>::type
|
|
ConvertReturn(intptr_t ret) {
|
|
return Object(ret);
|
|
}
|
|
|
|
// Convert back void return type (i.e. no return).
|
|
template <typename T>
|
|
static typename std::enable_if<std::is_void<T>::value, T>::type ConvertReturn(
|
|
intptr_t ret) {}
|
|
|
|
private:
|
|
static base::Mutex* redirection_mutex_;
|
|
static Redirection* redirection_;
|
|
|
|
static base::Mutex* i_cache_mutex_;
|
|
static base::CustomMatcherHashMap* i_cache_;
|
|
|
|
// Helper methods to convert arbitrary integer or pointer arguments to the
|
|
// needed generic argument type intptr_t.
|
|
|
|
// Convert integral argument to intptr_t.
|
|
template <typename T>
|
|
static typename std::enable_if<std::is_integral<T>::value, intptr_t>::type
|
|
ConvertArg(T arg) {
|
|
static_assert(sizeof(T) <= sizeof(intptr_t), "type bigger than ptrsize");
|
|
#if V8_TARGET_ARCH_MIPS64
|
|
// The MIPS64 calling convention is to sign extend all values, even unsigned
|
|
// ones.
|
|
using signed_t = typename std::make_signed<T>::type;
|
|
return static_cast<intptr_t>(static_cast<signed_t>(arg));
|
|
#else
|
|
// Standard C++ convertion: Sign-extend signed values, zero-extend unsigned
|
|
// values.
|
|
return static_cast<intptr_t>(arg);
|
|
#endif
|
|
}
|
|
|
|
// Convert pointer-typed argument to intptr_t.
|
|
template <typename T>
|
|
static typename std::enable_if<std::is_pointer<T>::value, intptr_t>::type
|
|
ConvertArg(T arg) {
|
|
return reinterpret_cast<intptr_t>(arg);
|
|
}
|
|
};
|
|
|
|
// When the generated code calls an external reference we need to catch that in
|
|
// the simulator. The external reference will be a function compiled for the
|
|
// host architecture. We need to call that function instead of trying to
|
|
// execute it with the simulator. We do that by redirecting the external
|
|
// reference to a trapping instruction that is handled by the simulator. We
|
|
// write the original destination of the jump just at a known offset from the
|
|
// trapping instruction so the simulator knows what to call.
|
|
//
|
|
// The following are trapping instructions used for various architectures:
|
|
// - V8_TARGET_ARCH_ARM: svc (Supervisor Call)
|
|
// - V8_TARGET_ARCH_ARM64: svc (Supervisor Call)
|
|
// - V8_TARGET_ARCH_MIPS: swi (software-interrupt)
|
|
// - V8_TARGET_ARCH_MIPS64: swi (software-interrupt)
|
|
// - V8_TARGET_ARCH_PPC: svc (Supervisor Call)
|
|
// - V8_TARGET_ARCH_S390: svc (Supervisor Call)
|
|
class Redirection {
|
|
public:
|
|
Redirection(Address external_function, ExternalReference::Type type);
|
|
|
|
Address address_of_instruction() {
|
|
#if ABI_USES_FUNCTION_DESCRIPTORS
|
|
return reinterpret_cast<Address>(function_descriptor_);
|
|
#else
|
|
return reinterpret_cast<Address>(&instruction_);
|
|
#endif
|
|
}
|
|
|
|
void* external_function() {
|
|
return reinterpret_cast<void*>(external_function_);
|
|
}
|
|
ExternalReference::Type type() { return type_; }
|
|
|
|
static Redirection* Get(Address external_function,
|
|
ExternalReference::Type type);
|
|
|
|
static Redirection* FromInstruction(Instruction* instruction) {
|
|
Address addr_of_instruction = reinterpret_cast<Address>(instruction);
|
|
Address addr_of_redirection =
|
|
addr_of_instruction - offsetof(Redirection, instruction_);
|
|
return reinterpret_cast<Redirection*>(addr_of_redirection);
|
|
}
|
|
|
|
static void* ReverseRedirection(intptr_t reg) {
|
|
Redirection* redirection = FromInstruction(
|
|
reinterpret_cast<Instruction*>(reinterpret_cast<void*>(reg)));
|
|
return redirection->external_function();
|
|
}
|
|
|
|
static void DeleteChain(Redirection* redirection) {
|
|
while (redirection != nullptr) {
|
|
Redirection* next = redirection->next_;
|
|
delete redirection;
|
|
redirection = next;
|
|
}
|
|
}
|
|
|
|
private:
|
|
Address external_function_;
|
|
uint32_t instruction_;
|
|
ExternalReference::Type type_;
|
|
Redirection* next_;
|
|
#if ABI_USES_FUNCTION_DESCRIPTORS
|
|
intptr_t function_descriptor_[3];
|
|
#endif
|
|
};
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // defined(USE_SIMULATOR)
|
|
#endif // V8_SIMULATOR_BASE_H_
|