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