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 { CastReturnValueTraits29 static R Cast(uintptr_t r) { return reinterpret_cast<R>(r); } RepresentationReturnValueTraits30 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