v8/test/cctest/compiler/call-tester.h
Clemens Hammacher 3d76d2a2dc [cctest] Refactor CallHelper to use variadic templates
Instead of explicitly instantiating six copies of each function for
zero to five arguments, define them as variadic template.
This avoids the arbitrary limit to five arguments, and avoids lots of
code duplication.

Drive-by fix: [iwyu] Add missing include.

R=mstarzinger@chromium.org

Change-Id: Id7edde3611ddfade16c7afbbf4b9000cedd76468
Reviewed-on: https://chromium-review.googlesource.com/496247
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45130}
2017-05-05 12:05:45 +00:00

212 lines
5.3 KiB
C++

// Copyright 2014 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_CCTEST_COMPILER_CALL_TESTER_H_
#define V8_CCTEST_COMPILER_CALL_TESTER_H_
#include "src/handles.h"
#include "src/simulator.h"
#include "test/cctest/compiler/c-signature.h"
#if V8_TARGET_ARCH_IA32
#if __GNUC__
#define V8_CDECL __attribute__((cdecl))
#else
#define V8_CDECL __cdecl
#endif
#else
#define V8_CDECL
#endif
namespace v8 {
namespace internal {
namespace compiler {
template <typename R>
inline R CastReturnValue(uintptr_t r) {
return reinterpret_cast<R>(r);
}
template <>
inline void CastReturnValue(uintptr_t r) {}
template <>
inline bool CastReturnValue(uintptr_t r) {
return static_cast<bool>(r);
}
template <>
inline int32_t CastReturnValue(uintptr_t r) {
return static_cast<int32_t>(r);
}
template <>
inline uint32_t CastReturnValue(uintptr_t r) {
return static_cast<uint32_t>(r);
}
template <>
inline int64_t CastReturnValue(uintptr_t r) {
return static_cast<int64_t>(r);
}
template <>
inline uint64_t CastReturnValue(uintptr_t r) {
return static_cast<uint64_t>(r);
}
template <>
inline int16_t CastReturnValue(uintptr_t r) {
return static_cast<int16_t>(r);
}
template <>
inline uint16_t CastReturnValue(uintptr_t r) {
return static_cast<uint16_t>(r);
}
template <>
inline int8_t CastReturnValue(uintptr_t r) {
return static_cast<int8_t>(r);
}
template <>
inline uint8_t CastReturnValue(uintptr_t r) {
return static_cast<uint8_t>(r);
}
template <>
inline double CastReturnValue(uintptr_t r) {
UNREACHABLE();
return 0.0;
}
template <typename R>
struct ParameterTraits {
static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
};
template <>
struct ParameterTraits<int*> {
static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
};
template <typename T>
struct ParameterTraits<T*> {
static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
};
#if !V8_TARGET_ARCH_32_BIT
// Additional template specialization required for mips64 to sign-extend
// parameters defined by calling convention.
template <>
struct ParameterTraits<int32_t> {
static int64_t Cast(int32_t r) { return static_cast<int64_t>(r); }
};
#if !V8_TARGET_ARCH_PPC64
template <>
struct ParameterTraits<uint32_t> {
static int64_t Cast(uint32_t r) {
return static_cast<int64_t>(static_cast<int32_t>(r));
}
};
#endif
#endif // !V8_TARGET_ARCH_64_BIT
template <typename R>
class CallHelper {
public:
explicit CallHelper(Isolate* isolate, MachineSignature* csig)
: csig_(csig), isolate_(isolate) {
USE(isolate_);
}
virtual ~CallHelper() {}
template <typename... Params>
R Call(Params... args) {
using FType = R(V8_CDECL*)(Params...);
CSignature::VerifyParams<Params...>(csig_);
return DoCall(FUNCTION_CAST<FType>(Generate()), args...);
}
protected:
MachineSignature* csig_;
virtual byte* Generate() = 0;
private:
#if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
Simulator* simulator = Simulator::current(isolate_);
return static_cast<uintptr_t>(simulator->CallInt64(f, args));
}
template <typename F, typename... Params>
R DoCall(F* f, Params... args) {
Simulator::CallArgument args_arr[] = {Simulator::CallArgument(args)...,
Simulator::CallArgument::End()};
return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args_arr));
}
#elif USE_SIMULATOR && \
(V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X)
uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
int64_t p3 = 0, int64_t p4 = 0, int64_t p5 = 0) {
Simulator* simulator = Simulator::current(isolate_);
return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
}
template <typename F, typename... Params>
R DoCall(F* f, Params... args) {
return CastReturnValue<R>(CallSimulator(
FUNCTION_ADDR(f), ParameterTraits<Params>::Cast(args)...));
}
#elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390)
uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
int32_t p3 = 0, int32_t p4 = 0, int32_t p5 = 0) {
Simulator* simulator = Simulator::current(isolate_);
return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
}
template <typename F, typename... Params>
R DoCall(F* f, Params... args) {
return CastReturnValue<R>(CallSimulator(
FUNCTION_ADDR(f), ParameterTraits<Params>::Cast(args)...));
}
#else
template <typename F, typename... Params>
R DoCall(F* f, Params... args) {
return f(args...);
}
#endif
Isolate* isolate_;
};
// A call helper that calls the given code object assuming C calling convention.
template <typename T>
class CodeRunner : public CallHelper<T> {
public:
CodeRunner(Isolate* isolate, Handle<Code> code, MachineSignature* csig)
: CallHelper<T>(isolate, csig), code_(code) {}
virtual ~CodeRunner() {}
virtual byte* Generate() { return code_->entry(); }
private:
Handle<Code> code_;
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_CCTEST_COMPILER_CALL_TESTER_H_