| // 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(); |
| } |
| |
| 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_ |