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/v8.h"
      9 
     10 #include "src/simulator.h"
     11 
     12 #if V8_TARGET_ARCH_IA32
     13 #if __GNUC__
     14 #define V8_CDECL __attribute__((cdecl))
     15 #else
     16 #define V8_CDECL __cdecl
     17 #endif
     18 #else
     19 #define V8_CDECL
     20 #endif
     21 
     22 namespace v8 {
     23 namespace internal {
     24 namespace compiler {
     25 
     26 // TODO(titzer): use c-signature.h instead of ReturnValueTraits
     27 template <typename R>
     28 struct ReturnValueTraits {
     29   static R Cast(uintptr_t r) { return reinterpret_cast<R>(r); }
     30   static MachineType Representation() {
     31     // TODO(dcarney): detect when R is of a subclass of Object* instead of this
     32     // type check.
     33     while (false) {
     34       *(static_cast<Object* volatile*>(0)) = static_cast<R>(0);
     35     }
     36     return kMachAnyTagged;
     37   }
     38 };
     39 
     40 template <>
     41 struct ReturnValueTraits<int32_t*> {
     42   static int32_t* Cast(uintptr_t r) { return reinterpret_cast<int32_t*>(r); }
     43   static MachineType Representation() { return kMachPtr; }
     44 };
     45 
     46 template <>
     47 struct ReturnValueTraits<void> {
     48   static void Cast(uintptr_t r) {}
     49   static MachineType Representation() { return kMachPtr; }
     50 };
     51 
     52 template <>
     53 struct ReturnValueTraits<bool> {
     54   static bool Cast(uintptr_t r) { return static_cast<bool>(r); }
     55   static MachineType Representation() { return kRepBit; }
     56 };
     57 
     58 template <>
     59 struct ReturnValueTraits<int32_t> {
     60   static int32_t Cast(uintptr_t r) { return static_cast<int32_t>(r); }
     61   static MachineType Representation() { return kMachInt32; }
     62 };
     63 
     64 template <>
     65 struct ReturnValueTraits<uint32_t> {
     66   static uint32_t Cast(uintptr_t r) { return static_cast<uint32_t>(r); }
     67   static MachineType Representation() { return kMachUint32; }
     68 };
     69 
     70 template <>
     71 struct ReturnValueTraits<int64_t> {
     72   static int64_t Cast(uintptr_t r) { return static_cast<int64_t>(r); }
     73   static MachineType Representation() { return kMachInt64; }
     74 };
     75 
     76 template <>
     77 struct ReturnValueTraits<uint64_t> {
     78   static uint64_t Cast(uintptr_t r) { return static_cast<uint64_t>(r); }
     79   static MachineType Representation() { return kMachUint64; }
     80 };
     81 
     82 template <>
     83 struct ReturnValueTraits<int16_t> {
     84   static int16_t Cast(uintptr_t r) { return static_cast<int16_t>(r); }
     85   static MachineType Representation() { return kMachInt16; }
     86 };
     87 
     88 template <>
     89 struct ReturnValueTraits<uint16_t> {
     90   static uint16_t Cast(uintptr_t r) { return static_cast<uint16_t>(r); }
     91   static MachineType Representation() { return kMachUint16; }
     92 };
     93 
     94 template <>
     95 struct ReturnValueTraits<int8_t> {
     96   static int8_t Cast(uintptr_t r) { return static_cast<int8_t>(r); }
     97   static MachineType Representation() { return kMachInt8; }
     98 };
     99 
    100 template <>
    101 struct ReturnValueTraits<uint8_t> {
    102   static uint8_t Cast(uintptr_t r) { return static_cast<uint8_t>(r); }
    103   static MachineType Representation() { return kMachUint8; }
    104 };
    105 
    106 template <>
    107 struct ReturnValueTraits<double> {
    108   static double Cast(uintptr_t r) {
    109     UNREACHABLE();
    110     return 0.0;
    111   }
    112   static MachineType Representation() { return kMachFloat64; }
    113 };
    114 
    115 
    116 template <typename R>
    117 struct ParameterTraits {
    118   static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); }
    119 };
    120 
    121 template <>
    122 struct ParameterTraits<int*> {
    123   static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); }
    124 };
    125 
    126 template <typename T>
    127 struct ParameterTraits<T*> {
    128   static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); }
    129 };
    130 
    131 class CallHelper {
    132  public:
    133   explicit CallHelper(Isolate* isolate, MachineSignature* machine_sig)
    134       : machine_sig_(machine_sig), isolate_(isolate) {
    135     USE(isolate_);
    136   }
    137   virtual ~CallHelper() {}
    138 
    139   static MachineSignature* MakeMachineSignature(
    140       Zone* zone, MachineType return_type, MachineType p0 = kMachNone,
    141       MachineType p1 = kMachNone, MachineType p2 = kMachNone,
    142       MachineType p3 = kMachNone, MachineType p4 = kMachNone) {
    143     // Count the number of parameters.
    144     size_t param_count = 5;
    145     MachineType types[] = {p0, p1, p2, p3, p4};
    146     while (param_count > 0 && types[param_count - 1] == kMachNone)
    147       param_count--;
    148     size_t return_count = return_type == kMachNone ? 0 : 1;
    149 
    150     // Build the machine signature.
    151     MachineSignature::Builder builder(zone, return_count, param_count);
    152     if (return_count > 0) builder.AddReturn(return_type);
    153     for (size_t i = 0; i < param_count; i++) {
    154       builder.AddParam(types[i]);
    155     }
    156     return builder.Build();
    157   }
    158 
    159  protected:
    160   MachineSignature* machine_sig_;
    161   void VerifyParameters(size_t parameter_count, MachineType* parameter_types) {
    162     CHECK(machine_sig_->parameter_count() == parameter_count);
    163     for (size_t i = 0; i < parameter_count; i++) {
    164       CHECK_EQ(machine_sig_->GetParam(i), parameter_types[i]);
    165     }
    166   }
    167   virtual byte* Generate() = 0;
    168 
    169  private:
    170 #if USE_SIMULATOR && V8_TARGET_ARCH_ARM64
    171   uintptr_t CallSimulator(byte* f, Simulator::CallArgument* args) {
    172     Simulator* simulator = Simulator::current(isolate_);
    173     return static_cast<uintptr_t>(simulator->CallInt64(f, args));
    174   }
    175 
    176   template <typename R, typename F>
    177   R DoCall(F* f) {
    178     Simulator::CallArgument args[] = {Simulator::CallArgument::End()};
    179     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
    180   }
    181   template <typename R, typename F, typename P1>
    182   R DoCall(F* f, P1 p1) {
    183     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
    184                                       Simulator::CallArgument::End()};
    185     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
    186   }
    187   template <typename R, typename F, typename P1, typename P2>
    188   R DoCall(F* f, P1 p1, P2 p2) {
    189     Simulator::CallArgument args[] = {Simulator::CallArgument(p1),
    190                                       Simulator::CallArgument(p2),
    191                                       Simulator::CallArgument::End()};
    192     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
    193   }
    194   template <typename R, typename F, typename P1, typename P2, typename P3>
    195   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    196     Simulator::CallArgument args[] = {
    197         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
    198         Simulator::CallArgument(p3), Simulator::CallArgument::End()};
    199     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
    200   }
    201   template <typename R, typename F, typename P1, typename P2, typename P3,
    202             typename P4>
    203   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    204     Simulator::CallArgument args[] = {
    205         Simulator::CallArgument(p1), Simulator::CallArgument(p2),
    206         Simulator::CallArgument(p3), Simulator::CallArgument(p4),
    207         Simulator::CallArgument::End()};
    208     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
    209   }
    210 #elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
    211   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
    212                           int32_t p3 = 0, int32_t p4 = 0) {
    213     Simulator* simulator = Simulator::current(isolate_);
    214     return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
    215   }
    216   template <typename R, typename F>
    217   R DoCall(F* f) {
    218     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
    219   }
    220   template <typename R, typename F, typename P1>
    221   R DoCall(F* f, P1 p1) {
    222     return ReturnValueTraits<R>::Cast(
    223         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
    224   }
    225   template <typename R, typename F, typename P1, typename P2>
    226   R DoCall(F* f, P1 p1, P2 p2) {
    227     return ReturnValueTraits<R>::Cast(
    228         CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    229                       ParameterTraits<P2>::Cast(p2)));
    230   }
    231   template <typename R, typename F, typename P1, typename P2, typename P3>
    232   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    233     return ReturnValueTraits<R>::Cast(CallSimulator(
    234         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    235         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
    236   }
    237   template <typename R, typename F, typename P1, typename P2, typename P3,
    238             typename P4>
    239   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    240     return ReturnValueTraits<R>::Cast(CallSimulator(
    241         FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
    242         ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
    243         ParameterTraits<P4>::Cast(p4)));
    244   }
    245 #else
    246   template <typename R, typename F>
    247   R DoCall(F* f) {
    248     return f();
    249   }
    250   template <typename R, typename F, typename P1>
    251   R DoCall(F* f, P1 p1) {
    252     return f(p1);
    253   }
    254   template <typename R, typename F, typename P1, typename P2>
    255   R DoCall(F* f, P1 p1, P2 p2) {
    256     return f(p1, p2);
    257   }
    258   template <typename R, typename F, typename P1, typename P2, typename P3>
    259   R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
    260     return f(p1, p2, p3);
    261   }
    262   template <typename R, typename F, typename P1, typename P2, typename P3,
    263             typename P4>
    264   R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
    265     return f(p1, p2, p3, p4);
    266   }
    267 #endif
    268 
    269 #ifndef DEBUG
    270   void VerifyParameters0() {}
    271 
    272   template <typename P1>
    273   void VerifyParameters1() {}
    274 
    275   template <typename P1, typename P2>
    276   void VerifyParameters2() {}
    277 
    278   template <typename P1, typename P2, typename P3>
    279   void VerifyParameters3() {}
    280 
    281   template <typename P1, typename P2, typename P3, typename P4>
    282   void VerifyParameters4() {}
    283 #else
    284   void VerifyParameters0() { VerifyParameters(0, NULL); }
    285 
    286   template <typename P1>
    287   void VerifyParameters1() {
    288     MachineType parameters[] = {ReturnValueTraits<P1>::Representation()};
    289     VerifyParameters(arraysize(parameters), parameters);
    290   }
    291 
    292   template <typename P1, typename P2>
    293   void VerifyParameters2() {
    294     MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
    295                                 ReturnValueTraits<P2>::Representation()};
    296     VerifyParameters(arraysize(parameters), parameters);
    297   }
    298 
    299   template <typename P1, typename P2, typename P3>
    300   void VerifyParameters3() {
    301     MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
    302                                 ReturnValueTraits<P2>::Representation(),
    303                                 ReturnValueTraits<P3>::Representation()};
    304     VerifyParameters(arraysize(parameters), parameters);
    305   }
    306 
    307   template <typename P1, typename P2, typename P3, typename P4>
    308   void VerifyParameters4() {
    309     MachineType parameters[] = {ReturnValueTraits<P1>::Representation(),
    310                                 ReturnValueTraits<P2>::Representation(),
    311                                 ReturnValueTraits<P3>::Representation(),
    312                                 ReturnValueTraits<P4>::Representation()};
    313     VerifyParameters(arraysize(parameters), parameters);
    314   }
    315 #endif
    316 
    317   // TODO(dcarney): replace Call() in CallHelper2 with these.
    318   template <typename R>
    319   R Call0() {
    320     typedef R V8_CDECL FType();
    321     VerifyParameters0();
    322     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()));
    323   }
    324 
    325   template <typename R, typename P1>
    326   R Call1(P1 p1) {
    327     typedef R V8_CDECL FType(P1);
    328     VerifyParameters1<P1>();
    329     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1);
    330   }
    331 
    332   template <typename R, typename P1, typename P2>
    333   R Call2(P1 p1, P2 p2) {
    334     typedef R V8_CDECL FType(P1, P2);
    335     VerifyParameters2<P1, P2>();
    336     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2);
    337   }
    338 
    339   template <typename R, typename P1, typename P2, typename P3>
    340   R Call3(P1 p1, P2 p2, P3 p3) {
    341     typedef R V8_CDECL FType(P1, P2, P3);
    342     VerifyParameters3<P1, P2, P3>();
    343     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3);
    344   }
    345 
    346   template <typename R, typename P1, typename P2, typename P3, typename P4>
    347   R Call4(P1 p1, P2 p2, P3 p3, P4 p4) {
    348     typedef R V8_CDECL FType(P1, P2, P3, P4);
    349     VerifyParameters4<P1, P2, P3, P4>();
    350     return DoCall<R>(FUNCTION_CAST<FType*>(Generate()), p1, p2, p3, p4);
    351   }
    352 
    353   template <typename R, typename C>
    354   friend class CallHelper2;
    355   Isolate* isolate_;
    356 };
    357 
    358 
    359 // TODO(dcarney): replace CallHelper with CallHelper2 and rename.
    360 template <typename R, typename C>
    361 class CallHelper2 {
    362  public:
    363   R Call() { return helper()->template Call0<R>(); }
    364 
    365   template <typename P1>
    366   R Call(P1 p1) {
    367     return helper()->template Call1<R>(p1);
    368   }
    369 
    370   template <typename P1, typename P2>
    371   R Call(P1 p1, P2 p2) {
    372     return helper()->template Call2<R>(p1, p2);
    373   }
    374 
    375   template <typename P1, typename P2, typename P3>
    376   R Call(P1 p1, P2 p2, P3 p3) {
    377     return helper()->template Call3<R>(p1, p2, p3);
    378   }
    379 
    380   template <typename P1, typename P2, typename P3, typename P4>
    381   R Call(P1 p1, P2 p2, P3 p3, P4 p4) {
    382     return helper()->template Call4<R>(p1, p2, p3, p4);
    383   }
    384 
    385  private:
    386   CallHelper* helper() { return static_cast<C*>(this); }
    387 };
    388 
    389 }  // namespace compiler
    390 }  // namespace internal
    391 }  // namespace v8
    392 
    393 #endif  // V8_CCTEST_COMPILER_CALL_TESTER_H_
    394