Home | History | Annotate | Download | only in compiler
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_CCTEST_COMPILER_CALL_TESTER_H_
      6 #define V8_CCTEST_COMPILER_CALL_TESTER_H_
      7 
      8 #include "src/simulator.h"
      9 #include "test/cctest/compiler/c-signature.h"
     10 
     11 #if V8_TARGET_ARCH_IA32
     12 #if __GNUC__
     13 #define V8_CDECL __attribute__((cdecl))
     14 #else
     15 #define V8_CDECL __cdecl
     16 #endif
     17 #else
     18 #define V8_CDECL
     19 #endif
     20 
     21 namespace v8 {
     22 namespace internal {
     23 namespace compiler {
     24 
     25 template <typename R>
     26 inline R CastReturnValue(uintptr_t r) {
     27   return reinterpret_cast<R>(r);
     28 }
     29 
     30 template <>
     31 inline void CastReturnValue(uintptr_t r) {}
     32 
     33 template <>
     34 inline bool CastReturnValue(uintptr_t r) {
     35   return static_cast<bool>(r);
     36 }
     37 
     38 template <>
     39 inline int32_t CastReturnValue(uintptr_t r) {
     40   return static_cast<int32_t>(r);
     41 }
     42 
     43 template <>
     44 inline uint32_t CastReturnValue(uintptr_t r) {
     45   return static_cast<uint32_t>(r);
     46 }
     47 
     48 template <>
     49 inline int64_t CastReturnValue(uintptr_t r) {
     50   return static_cast<int64_t>(r);
     51 }
     52 
     53 template <>
     54 inline uint64_t CastReturnValue(uintptr_t r) {
     55   return static_cast<uint64_t>(r);
     56 }
     57 
     58 template <>
     59 inline int16_t CastReturnValue(uintptr_t r) {
     60   return static_cast<int16_t>(r);
     61 }
     62 
     63 template <>
     64 inline uint16_t CastReturnValue(uintptr_t r) {
     65   return static_cast<uint16_t>(r);
     66 }
     67 
     68 template <>
     69 inline int8_t CastReturnValue(uintptr_t r) {
     70   return static_cast<int8_t>(r);
     71 }
     72 
     73 template <>
     74 inline uint8_t CastReturnValue(uintptr_t r) {
     75   return static_cast<uint8_t>(r);
     76 }
     77 
     78 template <>
     79 inline double CastReturnValue(uintptr_t r) {
     80   UNREACHABLE();
     81   return 0.0;
     82 }
     83 
     84 template <typename R>
     85 struct ParameterTraits {
     86   static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
     87 };
     88 
     89 template <>
     90 struct ParameterTraits<int*> {
     91   static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
     92 };
     93 
     94 template <typename T>
     95 struct ParameterTraits<T*> {
     96   static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
     97 };
     98 
     99 
    100 #if !V8_TARGET_ARCH_32_BIT
    101 
    102 // Additional template specialization required for mips64 to sign-extend
    103 // parameters defined by calling convention.
    104 template <>
    105 struct ParameterTraits<int32_t> {
    106   static int64_t Cast(int32_t r) { return static_cast<int64_t>(r); }
    107 };
    108 
    109 #if !V8_TARGET_ARCH_PPC64
    110 template <>
    111 struct ParameterTraits<uint32_t> {
    112   static int64_t Cast(uint32_t r) {
    113     return static_cast<int64_t>(static_cast<int32_t>(r));
    114   }
    115 };
    116 #endif
    117 
    118 #endif  // !V8_TARGET_ARCH_64_BIT
    119 
    120 
    121 template <typename R>
    122 class CallHelper {
    123  public:
    124   explicit CallHelper(Isolate* isolate, MachineSignature* csig)
    125       : csig_(csig), isolate_(isolate) {
    126     USE(isolate_);
    127   }
    128   virtual ~CallHelper() {}
    129 
    130   R Call() {
    131     typedef R V8_CDECL FType();
    132     CSignature::VerifyParams(csig_);
    133     return DoCall(FUNCTION_CAST<FType*>(Generate()));
    134   }
    135 
    136   template <typename P1>
    137   R Call(P1 p1) {
    138     typedef R V8_CDECL FType(P1);
    139     CSignature::VerifyParams<P1>(csig_);
    140     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1);
    141   }
    142 
    143   template <typename P1, typename P2>
    144   R Call(P1 p1, P2 p2) {
    145     typedef R V8_CDECL FType(P1, P2);
    146     CSignature::VerifyParams<P1, P2>(csig_);
    147     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2);
    148   }
    149 
    150   template <typename P1, typename P2, typename P3>
    151   R Call(P1 p1, P2 p2, P3 p3) {
    152     typedef R V8_CDECL FType(P1, P2, P3);
    153     CSignature::VerifyParams<P1, P2, P3>(csig_);
    154     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
    155   }
    156 
    157   template <typename P1, typename P2, typename P3, typename P4>
    158   R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
    159     typedef R V8_CDECL FType(P1, P2, P3, P4);
    160     CSignature::VerifyParams<P1, P2, P3, P4>(csig_);
    161     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
    162   }
    163 
    164   template <typename P1, typename P2, typename P3, typename P4, typename P5>
    165   R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
    166     typedef R V8_CDECL FType(P1, P2, P3, P4, P5);
    167     CSignature::VerifyParams<P1, P2, P3, P4, P5>(csig_);
    168     return DoCall(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4, p5);
    169   }
    170 
    171  protected:
    172   MachineSignature* csig_;
    173 
    174   virtual byte* Generate() = 0;
    175 
    176  private:
    177 #if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
    178   uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
    179     Simulator* simulator = Simulator::current(isolate_);
    180     return static_cast<uintptr_t>(simulator->CallInt64(f, args));
    181   }
    182 
    183   template <typename F>
    184   R DoCall(F* f) {
    185     Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
    186     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
    187   }
    188   template <typename F, typename P1>
    189   R DoCall(F* f, P1 p1) {
    190     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
    191                                       Simulator::CallArgument::End()};
    192     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
    193   }
    194   template <typename F, typename P1, typename P2>
    195   R DoCall(F* f, P1 p1, P2 p2) {
    196     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
    197                                       Simulator::CallArgument(p2),
    198                                       Simulator::CallArgument::End()};
    199     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
    200   }
    201   template <typename F, typename P1, typename P2, typename P3>
    202   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    203     Simulator::CallArgument args[] = {
    204         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
    205         Simulator::CallArgument(p3), Simulator::CallArgument::End()};
    206     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
    207   }
    208   template <typename F, typename P1, typename P2, typename P3, typename P4>
    209   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    210     Simulator::CallArgument args[] = {
    211         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
    212         Simulator::CallArgument(p3), Simulator::CallArgument(p4),
    213         Simulator::CallArgument::End()};
    214     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
    215   }
    216   template <typename F, typename P1, typename P2, typename P3, typename P4,
    217             typename P5>
    218   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
    219     Simulator::CallArgument args[] = {
    220         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
    221         Simulator::CallArgument(p3), Simulator::CallArgument(p4),
    222         Simulator::CallArgument(p5), Simulator::CallArgument::End()};
    223     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f), args));
    224   }
    225 #elif USE_SIMULATOR && \
    226     (V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390X)
    227   uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
    228                           int64_t p3 = 0, int64_t p4 = 0, int64_t p5 = 0) {
    229     Simulator* simulator = Simulator::current(isolate_);
    230     return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
    231   }
    232 
    233 
    234   template <typename F>
    235   R DoCall(F* f) {
    236     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f)));
    237   }
    238   template <typename F, typename P1>
    239   R DoCall(F* f, P1 p1) {
    240     return CastReturnValue<R>(
    241         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
    242   }
    243   template <typename F, typename P1, typename P2>
    244   R DoCall(F* f, P1 p1, P2 p2) {
    245     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f),
    246                                             ParameterTraits<P1>::Cast(p1),
    247                                             ParameterTraits<P2>::Cast(p2)));
    248   }
    249   template <typename F, typename P1, typename P2, typename P3>
    250   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    251     return CastReturnValue<R>(CallSimulator(
    252         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    253         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
    254   }
    255   template <typename F, typename P1, typename P2, typename P3, typename P4>
    256   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    257     return CastReturnValue<R>(CallSimulator(
    258         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    259         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
    260         ParameterTraits<P4>::Cast(p4)));
    261   }
    262   template <typename F, typename P1, typename P2, typename P3, typename P4,
    263             typename P5>
    264   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
    265     return CastReturnValue<R>(CallSimulator(
    266         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    267         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
    268         ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
    269   }
    270 #elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS || \
    271                         V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_S390)
    272   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
    273                           int32_t p3 = 0, int32_t p4 = 0, int32_t p5 = 0) {
    274     Simulator* simulator = Simulator::current(isolate_);
    275     return static_cast<uintptr_t>(simulator->Call(f, 5, p1, p2, p3, p4, p5));
    276   }
    277   template <typename F>
    278   R DoCall(F* f) {
    279     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f)));
    280   }
    281   template <typename F, typename P1>
    282   R DoCall(F* f, P1 p1) {
    283     return CastReturnValue<R>(
    284         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
    285   }
    286   template <typename F, typename P1, typename P2>
    287   R DoCall(F* f, P1 p1, P2 p2) {
    288     return CastReturnValue<R>(CallSimulator(FUNCTION_ADDR(f),
    289                                             ParameterTraits<P1>::Cast(p1),
    290                                             ParameterTraits<P2>::Cast(p2)));
    291   }
    292   template <typename F, typename P1, typename P2, typename P3>
    293   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    294     return CastReturnValue<R>(CallSimulator(
    295         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    296         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
    297   }
    298   template <typename F, typename P1, typename P2, typename P3, typename P4>
    299   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    300     return CastReturnValue<R>(CallSimulator(
    301         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    302         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
    303         ParameterTraits<P4>::Cast(p4)));
    304   }
    305   template <typename F, typename P1, typename P2, typename P3, typename P4,
    306             typename P5>
    307   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
    308     return CastReturnValue<R>(CallSimulator(
    309         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    310         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
    311         ParameterTraits<P4>::Cast(p4), ParameterTraits<P5>::Cast(p5)));
    312   }
    313 #else
    314   template <typename F>
    315   R DoCall(F* f) {
    316     return f();
    317   }
    318   template <typename F, typename P1>
    319   R DoCall(F* f, P1 p1) {
    320     return f(p1);
    321   }
    322   template <typename F, typename P1, typename P2>
    323   R DoCall(F* f, P1 p1, P2 p2) {
    324     return f(p1, p2);
    325   }
    326   template <typename F, typename P1, typename P2, typename P3>
    327   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    328     return f(p1, p2, p3);
    329   }
    330   template <typename F, typename P1, typename P2, typename P3, typename P4>
    331   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    332     return f(p1, p2, p3, p4);
    333   }
    334   template <typename F, typename P1, typename P2, typename P3, typename P4,
    335             typename P5>
    336   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
    337     return f(p1, p2, p3, p4, p5);
    338   }
    339 #endif
    340 
    341   Isolate* isolate_;
    342 };
    343 
    344 // A call helper that calls the given code object assuming C calling convention.
    345 template <typename T>
    346 class CodeRunner : public CallHelper<T> {
    347  public:
    348   CodeRunner(Isolate* isolate, Handle<Code> code, MachineSignature* csig)
    349       : CallHelper<T>(isolate, csig), code_(code) {}
    350   virtual ~CodeRunner() {}
    351 
    352   virtual byte* Generate() { return code_->entry(); }
    353 
    354  private:
    355   Handle<Code> code_;
    356 };
    357 
    358 
    359 }  // namespace compiler
    360 }  // namespace internal
    361 }  // namespace v8
    362 
    363 #endif  // V8_CCTEST_COMPILER_CALL_TESTER_H_
    364