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 22namespace v8 { 23namespace internal { 24namespace compiler { 25 26// TODO(titzer): use c-signature.h instead of ReturnValueTraits 27template <typename R> 28struct 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 40template <> 41struct 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 46template <> 47struct ReturnValueTraits<void> { 48 static void Cast(uintptr_t r) {} 49 static MachineType Representation() { return kMachPtr; } 50}; 51 52template <> 53struct ReturnValueTraits<bool> { 54 static bool Cast(uintptr_t r) { return static_cast<bool>(r); } 55 static MachineType Representation() { return kRepBit; } 56}; 57 58template <> 59struct 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 64template <> 65struct 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 70template <> 71struct 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 76template <> 77struct 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 82template <> 83struct 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 88template <> 89struct 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 94template <> 95struct 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 100template <> 101struct 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 106template <> 107struct 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 116template <typename R> 117struct ParameterTraits { 118 static uintptr_t Cast(R r) { return static_cast<uintptr_t>(r); } 119}; 120 121template <> 122struct ParameterTraits<int*> { 123 static uintptr_t Cast(int* r) { return reinterpret_cast<uintptr_t>(r); } 124}; 125 126template <typename T> 127struct ParameterTraits<T*> { 128 static uintptr_t Cast(void* r) { return reinterpret_cast<uintptr_t>(r); } 129}; 130 131class 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. 360template <typename R, typename C> 361class 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