// 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/v8.h" #include "src/simulator.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 { // TODO(titzer): move MachineType selection for C types into machine-type.h template struct ReturnValueTraits { static R Cast(uintptr_t r) { return reinterpret_cast(r); } static MachineType Representation() { // TODO(dcarney): detect when R is of a subclass of Object* instead of this // type check. while (false) { *(static_cast(0)) = static_cast(0); } return kMachAnyTagged; } }; template <> struct ReturnValueTraits { static int32_t* Cast(uintptr_t r) { return reinterpret_cast(r); } static MachineType Representation() { return kMachPtr; } }; template <> struct ReturnValueTraits { static void Cast(uintptr_t r) {} static MachineType Representation() { return kMachPtr; } }; template <> struct ReturnValueTraits { static bool Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kRepBit; } }; template <> struct ReturnValueTraits { static int32_t Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kMachInt32; } }; template <> struct ReturnValueTraits { static uint32_t Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kMachUint32; } }; template <> struct ReturnValueTraits { static int64_t Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kMachInt64; } }; template <> struct ReturnValueTraits { static uint64_t Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kMachUint64; } }; template <> struct ReturnValueTraits { static int16_t Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kMachInt16; } }; template <> struct ReturnValueTraits { static int8_t Cast(uintptr_t r) { return static_cast(r); } static MachineType Representation() { return kMachInt8; } }; template <> struct ReturnValueTraits { static double Cast(uintptr_t r) { UNREACHABLE(); return 0.0; } static MachineType Representation() { return kMachFloat64; } }; template struct ParameterTraits { static uintptr_t Cast(R r) { return static_cast(r); } }; template <> struct ParameterTraits { static uintptr_t Cast(int* r) { return reinterpret_cast(r); } }; template struct ParameterTraits { static uintptr_t Cast(void* r) { return reinterpret_cast(r); } }; class CallHelper { public: explicit CallHelper(Isolate* isolate) : isolate_(isolate) { USE(isolate_); } virtual ~CallHelper() {} static MachineCallDescriptorBuilder* ToCallDescriptorBuilder( Zone* zone, MachineType return_type, MachineType p0 = kMachNone, MachineType p1 = kMachNone, MachineType p2 = kMachNone, MachineType p3 = kMachNone, MachineType p4 = kMachNone) { const int kSize = 5; MachineType* params = zone->NewArray(kSize); params[0] = p0; params[1] = p1; params[2] = p2; params[3] = p3; params[4] = p4; int parameter_count = 0; for (int i = 0; i < kSize; ++i) { if (params[i] == kMachNone) { break; } parameter_count++; } return new (zone) MachineCallDescriptorBuilder(return_type, parameter_count, params); } protected: virtual void VerifyParameters(int parameter_count, MachineType* parameters) = 0; 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(simulator->CallInt64(f, args)); } template R DoCall(F* f) { Simulator::CallArgument args[] = {Simulator::CallArgument::End()}; return ReturnValueTraits::Cast(CallSimulator(FUNCTION_ADDR(f), args)); } template R DoCall(F* f, P1 p1) { Simulator::CallArgument args[] = {Simulator::CallArgument(p1), Simulator::CallArgument::End()}; return ReturnValueTraits::Cast(CallSimulator(FUNCTION_ADDR(f), args)); } template R DoCall(F* f, P1 p1, P2 p2) { Simulator::CallArgument args[] = {Simulator::CallArgument(p1), Simulator::CallArgument(p2), Simulator::CallArgument::End()}; return ReturnValueTraits::Cast(CallSimulator(FUNCTION_ADDR(f), args)); } template R DoCall(F* f, P1 p1, P2 p2, P3 p3) { Simulator::CallArgument args[] = { Simulator::CallArgument(p1), Simulator::CallArgument(p2), Simulator::CallArgument(p3), Simulator::CallArgument::End()}; return ReturnValueTraits::Cast(CallSimulator(FUNCTION_ADDR(f), args)); } template R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { Simulator::CallArgument args[] = { Simulator::CallArgument(p1), Simulator::CallArgument(p2), Simulator::CallArgument(p3), Simulator::CallArgument(p4), Simulator::CallArgument::End()}; return ReturnValueTraits::Cast(CallSimulator(FUNCTION_ADDR(f), args)); } #elif USE_SIMULATOR && V8_TARGET_ARCH_ARM uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0, int32_t p3 = 0, int32_t p4 = 0) { Simulator* simulator = Simulator::current(isolate_); return static_cast(simulator->Call(f, 4, p1, p2, p3, p4)); } template R DoCall(F* f) { return ReturnValueTraits::Cast(CallSimulator(FUNCTION_ADDR(f))); } template R DoCall(F* f, P1 p1) { return ReturnValueTraits::Cast( CallSimulator(FUNCTION_ADDR(f), ParameterTraits::Cast(p1))); } template R DoCall(F* f, P1 p1, P2 p2) { return ReturnValueTraits::Cast( CallSimulator(FUNCTION_ADDR(f), ParameterTraits::Cast(p1), ParameterTraits::Cast(p2))); } template R DoCall(F* f, P1 p1, P2 p2, P3 p3) { return ReturnValueTraits::Cast(CallSimulator( FUNCTION_ADDR(f), ParameterTraits::Cast(p1), ParameterTraits::Cast(p2), ParameterTraits::Cast(p3))); } template R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { return ReturnValueTraits::Cast(CallSimulator( FUNCTION_ADDR(f), ParameterTraits::Cast(p1), ParameterTraits::Cast(p2), ParameterTraits::Cast(p3), ParameterTraits::Cast(p4))); } #else template R DoCall(F* f) { return f(); } template R DoCall(F* f, P1 p1) { return f(p1); } template R DoCall(F* f, P1 p1, P2 p2) { return f(p1, p2); } template R DoCall(F* f, P1 p1, P2 p2, P3 p3) { return f(p1, p2, p3); } template R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) { return f(p1, p2, p3, p4); } #endif #ifndef DEBUG void VerifyParameters0() {} template void VerifyParameters1() {} template void VerifyParameters2() {} template void VerifyParameters3() {} template void VerifyParameters4() {} #else void VerifyParameters0() { VerifyParameters(0, NULL); } template void VerifyParameters1() { MachineType parameters[] = {ReturnValueTraits::Representation()}; VerifyParameters(ARRAY_SIZE(parameters), parameters); } template void VerifyParameters2() { MachineType parameters[] = {ReturnValueTraits::Representation(), ReturnValueTraits::Representation()}; VerifyParameters(ARRAY_SIZE(parameters), parameters); } template void VerifyParameters3() { MachineType parameters[] = {ReturnValueTraits::Representation(), ReturnValueTraits::Representation(), ReturnValueTraits::Representation()}; VerifyParameters(ARRAY_SIZE(parameters), parameters); } template void VerifyParameters4() { MachineType parameters[] = {ReturnValueTraits::Representation(), ReturnValueTraits::Representation(), ReturnValueTraits::Representation(), ReturnValueTraits::Representation()}; VerifyParameters(ARRAY_SIZE(parameters), parameters); } #endif // TODO(dcarney): replace Call() in CallHelper2 with these. template R Call0() { typedef R V8_CDECL FType(); VerifyParameters0(); return DoCall(FUNCTION_CAST(Generate())); } template R Call1(P1 p1) { typedef R V8_CDECL FType(P1); VerifyParameters1(); return DoCall(FUNCTION_CAST(Generate()), p1); } template R Call2(P1 p1, P2 p2) { typedef R V8_CDECL FType(P1, P2); VerifyParameters2(); return DoCall(FUNCTION_CAST(Generate()), p1, p2); } template R Call3(P1 p1, P2 p2, P3 p3) { typedef R V8_CDECL FType(P1, P2, P3); VerifyParameters3(); return DoCall(FUNCTION_CAST(Generate()), p1, p2, p3); } template R Call4(P1 p1, P2 p2, P3 p3, P4 p4) { typedef R V8_CDECL FType(P1, P2, P3, P4); VerifyParameters4(); return DoCall(FUNCTION_CAST(Generate()), p1, p2, p3, p4); } template friend class CallHelper2; Isolate* isolate_; }; // TODO(dcarney): replace CallHelper with CallHelper2 and rename. template class CallHelper2 { public: R Call() { return helper()->template Call0(); } template R Call(P1 p1) { return helper()->template Call1(p1); } template R Call(P1 p1, P2 p2) { return helper()->template Call2(p1, p2); } template R Call(P1 p1, P2 p2, P3 p3) { return helper()->template Call3(p1, p2, p3); } template R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return helper()->template Call4(p1, p2, p3, p4); } private: CallHelper* helper() { return static_cast(this); } }; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_CCTEST_COMPILER_CALL_TESTER_H_