this repo has no description
at trunk 743 lines 27 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "capi-trampolines.h" 3 4#include "api-handle.h" 5#include "capi.h" 6#include "dict-builtins.h" 7#include "runtime.h" 8#include "thread.h" 9 10namespace py { 11 12static const word kMaxStackArguments = 6; 13 14// method no args 15 16static RawObject callMethNoArgs(Thread* thread, const Function& function, 17 const Object& self) { 18 HandleScope scope(thread); 19 Int address(&scope, function.code()); 20 binaryfunc method = bit_cast<binaryfunc>(address.asCPtr()); 21 PyObject* self_obj = self.isUnbound() 22 ? nullptr 23 : ApiHandle::newReference(thread->runtime(), *self); 24 PyObject* pyresult = (*method)(self_obj, nullptr); 25 Object result(&scope, ApiHandle::checkFunctionResult(thread, pyresult)); 26 if (self_obj != nullptr) { 27 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 28 } 29 return *result; 30} 31 32static RawObject raiseTypeErrorMustBeBound(Thread* thread, 33 const Function& function) { 34 HandleScope scope(thread); 35 Str function_name(&scope, function.name()); 36 return thread->raiseWithFmt( 37 LayoutId::kTypeError, "'%S' must be bound to an object", &function_name); 38} 39 40static RawObject raiseTypeErrorNoArguments(Thread* thread, 41 const Function& function, 42 word nargs) { 43 HandleScope scope(thread); 44 Str function_name(&scope, function.name()); 45 if (nargs == 0) { 46 return raiseTypeErrorMustBeBound(thread, function); 47 } 48 return thread->raiseWithFmt(LayoutId::kTypeError, 49 "'%S' takes no arguments (%w given)", 50 &function_name, nargs - 1); 51} 52 53static RawObject raiseTypeErrorNoKeywordArguments(Thread* thread, 54 const Function& function) { 55 HandleScope scope(thread); 56 Str function_name(&scope, function.name()); 57 return thread->raiseWithFmt( 58 LayoutId::kTypeError, "'%S' takes no keyword arguments", &function_name); 59} 60 61RawObject methodTrampolineNoArgs(Thread* thread, word nargs) { 62 HandleScope scope(thread); 63 Function function(&scope, thread->stackPeek(nargs)); 64 if (nargs != 1) { 65 RawObject result = raiseTypeErrorNoArguments(thread, function, nargs); 66 thread->stackDrop(nargs + 1); 67 return result; 68 } 69 Object self(&scope, thread->stackPeek(0)); 70 RawObject result = callMethNoArgs(thread, function, self); 71 thread->stackDrop(nargs + 1); 72 return result; 73} 74 75RawObject methodTrampolineNoArgsKw(Thread* thread, word nargs) { 76 HandleScope scope(thread); 77 Function function(&scope, thread->stackPeek(nargs + 1)); 78 Tuple kw_names(&scope, thread->stackPeek(0)); 79 if (kw_names.length() != 0) { 80 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 81 thread->stackDrop(nargs + 2); 82 return result; 83 } 84 if (nargs != 1) { 85 RawObject result = raiseTypeErrorNoArguments(thread, function, nargs); 86 thread->stackDrop(nargs + 2); 87 return result; 88 } 89 Object self(&scope, thread->stackPeek(1)); 90 RawObject result = callMethNoArgs(thread, function, self); 91 thread->stackDrop(nargs + 2); 92 return result; 93} 94 95RawObject methodTrampolineNoArgsEx(Thread* thread, word flags) { 96 HandleScope scope(thread); 97 bool has_varkeywords = flags & CallFunctionExFlag::VAR_KEYWORDS; 98 Function function(&scope, thread->stackPeek(has_varkeywords + 1)); 99 Tuple args(&scope, thread->stackPeek(has_varkeywords)); 100 if (has_varkeywords) { 101 Object kw_args(&scope, thread->stackTop()); 102 if (!kw_args.isDict()) UNIMPLEMENTED("mapping kwargs"); 103 if (Dict::cast(*kw_args).numItems() != 0) { 104 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 105 thread->stackDrop(has_varkeywords + 2); 106 return result; 107 } 108 } 109 word args_length = args.length(); 110 if (args_length != 1) { 111 RawObject result = raiseTypeErrorNoArguments(thread, function, args_length); 112 thread->stackDrop(has_varkeywords + 2); 113 return result; 114 } 115 Object self(&scope, args.at(0)); 116 RawObject result = callMethNoArgs(thread, function, self); 117 thread->stackDrop(has_varkeywords + 2); 118 return result; 119} 120 121// method one arg 122 123static RawObject raiseTypeErrorOneArgument(Thread* thread, 124 const Function& function, 125 word nargs) { 126 HandleScope scope(thread); 127 Str function_name(&scope, function.name()); 128 if (nargs == 0) { 129 return raiseTypeErrorMustBeBound(thread, function); 130 } 131 return thread->raiseWithFmt(LayoutId::kTypeError, 132 "'%S' takes exactly one argument (%w given)", 133 &function_name, nargs - 1); 134} 135 136static RawObject callMethOneArg(Thread* thread, const Function& function, 137 const Object& self, const Object& arg) { 138 HandleScope scope(thread); 139 Int address(&scope, function.code()); 140 binaryfunc method = bit_cast<binaryfunc>(address.asCPtr()); 141 Runtime* runtime = thread->runtime(); 142 PyObject* self_obj = 143 self.isUnbound() ? nullptr : ApiHandle::newReference(runtime, *self); 144 PyObject* arg_obj = ApiHandle::newReference(runtime, *arg); 145 PyObject* pyresult = (*method)(self_obj, arg_obj); 146 Object result(&scope, ApiHandle::checkFunctionResult(thread, pyresult)); 147 if (self_obj != nullptr) { 148 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 149 } 150 ApiHandle::decref(ApiHandle::fromPyObject(arg_obj)); 151 return *result; 152} 153 154RawObject methodTrampolineOneArg(Thread* thread, word nargs) { 155 HandleScope scope(thread); 156 Function function(&scope, thread->stackPeek(nargs)); 157 if (nargs != 2) { 158 RawObject result = raiseTypeErrorOneArgument(thread, function, nargs); 159 thread->stackDrop(nargs + 1); 160 return result; 161 } 162 Object self(&scope, thread->stackPeek(1)); 163 Object arg(&scope, thread->stackPeek(0)); 164 RawObject result = callMethOneArg(thread, function, self, arg); 165 thread->stackDrop(nargs + 1); 166 return result; 167} 168 169RawObject methodTrampolineOneArgKw(Thread* thread, word nargs) { 170 HandleScope scope(thread); 171 Function function(&scope, thread->stackPeek(nargs + 1)); 172 Tuple kw_names(&scope, thread->stackPeek(0)); 173 if (kw_names.length() != 0) { 174 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 175 thread->stackDrop(nargs + 2); 176 return result; 177 } 178 if (nargs != 2) { 179 RawObject result = raiseTypeErrorOneArgument(thread, function, nargs); 180 thread->stackDrop(nargs + 2); 181 return result; 182 } 183 Object self(&scope, thread->stackPeek(2)); 184 Object arg(&scope, thread->stackPeek(1)); 185 RawObject result = callMethOneArg(thread, function, self, arg); 186 thread->stackDrop(nargs + 2); 187 return result; 188} 189 190RawObject methodTrampolineOneArgEx(Thread* thread, word flags) { 191 HandleScope scope(thread); 192 bool has_varkeywords = flags & CallFunctionExFlag::VAR_KEYWORDS; 193 Function function(&scope, thread->stackPeek(has_varkeywords + 1)); 194 if (has_varkeywords) { 195 Object kw_args(&scope, thread->stackTop()); 196 if (!kw_args.isDict()) UNIMPLEMENTED("mapping kwargs"); 197 if (Dict::cast(*kw_args).numItems() != 0) { 198 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 199 thread->stackDrop(has_varkeywords + 2); 200 return result; 201 } 202 } 203 Tuple varargs(&scope, thread->stackPeek(has_varkeywords)); 204 if (varargs.length() != 2) { 205 RawObject result = 206 raiseTypeErrorOneArgument(thread, function, varargs.length()); 207 thread->stackDrop(has_varkeywords + 2); 208 return result; 209 } 210 Object self(&scope, varargs.at(0)); 211 Object arg(&scope, varargs.at(1)); 212 RawObject result = callMethOneArg(thread, function, self, arg); 213 thread->stackDrop(has_varkeywords + 2); 214 return result; 215} 216 217// callMethVarArgs 218 219static RawObject callMethVarArgs(Thread* thread, const Function& function, 220 const Object& self, const Object& varargs) { 221 HandleScope scope(thread); 222 Int address(&scope, function.code()); 223 binaryfunc method = bit_cast<binaryfunc>(address.asCPtr()); 224 Runtime* runtime = thread->runtime(); 225 PyObject* self_obj = 226 self.isUnbound() ? nullptr : ApiHandle::newReference(runtime, *self); 227 PyObject* varargs_obj = ApiHandle::newReference(runtime, *varargs); 228 PyObject* pyresult = (*method)(self_obj, varargs_obj); 229 Object result(&scope, ApiHandle::checkFunctionResult(thread, pyresult)); 230 if (self_obj != nullptr) { 231 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 232 } 233 ApiHandle::decref(ApiHandle::fromPyObject(varargs_obj)); 234 return *result; 235} 236 237RawObject methodTrampolineVarArgs(Thread* thread, word nargs) { 238 HandleScope scope(thread); 239 Function function(&scope, thread->stackPeek(nargs)); 240 if (nargs == 0) { 241 RawObject result = raiseTypeErrorMustBeBound(thread, function); 242 thread->stackDrop(nargs + 1); 243 return result; 244 } 245 Object self(&scope, thread->stackPeek(nargs - 1)); 246 Object varargs_obj(&scope, NoneType::object()); 247 word num_varargs = nargs - 1; 248 if (num_varargs > 0) { 249 MutableTuple varargs(&scope, 250 thread->runtime()->newMutableTuple(num_varargs)); 251 for (word i = 0; i < num_varargs; i++) { 252 varargs.atPut(num_varargs - i - 1, thread->stackPeek(i)); 253 } 254 varargs_obj = varargs.becomeImmutable(); 255 } else { 256 varargs_obj = thread->runtime()->emptyTuple(); 257 } 258 RawObject result = callMethVarArgs(thread, function, self, varargs_obj); 259 thread->stackDrop(nargs + 1); 260 return result; 261} 262 263RawObject methodTrampolineVarArgsKw(Thread* thread, word nargs) { 264 HandleScope scope(thread); 265 Function function(&scope, thread->stackPeek(nargs + 1)); 266 Tuple kw_names(&scope, thread->stackPeek(0)); 267 if (kw_names.length() != 0) { 268 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 269 thread->stackDrop(nargs + 2); 270 return result; 271 } 272 if (nargs == 0) { 273 RawObject result = raiseTypeErrorMustBeBound(thread, function); 274 thread->stackDrop(nargs + 2); 275 return result; 276 } 277 Object self(&scope, thread->stackPeek(nargs)); 278 Object varargs_obj(&scope, NoneType::object()); 279 word num_varargs = nargs - 1; 280 if (num_varargs > 0) { 281 MutableTuple varargs(&scope, 282 thread->runtime()->newMutableTuple(num_varargs)); 283 for (word i = 0; i < num_varargs; i++) { 284 varargs.atPut(i, thread->stackPeek(num_varargs - i)); 285 } 286 varargs_obj = varargs.becomeImmutable(); 287 } else { 288 varargs_obj = thread->runtime()->emptyTuple(); 289 } 290 RawObject result = callMethVarArgs(thread, function, self, varargs_obj); 291 thread->stackDrop(nargs + 2); 292 return result; 293} 294 295RawObject methodTrampolineVarArgsEx(Thread* thread, word flags) { 296 HandleScope scope(thread); 297 bool has_varkeywords = flags & CallFunctionExFlag::VAR_KEYWORDS; 298 Function function(&scope, thread->stackPeek(has_varkeywords + 1)); 299 if (has_varkeywords) { 300 Object kw_args(&scope, thread->stackTop()); 301 if (!kw_args.isDict()) UNIMPLEMENTED("mapping kwargs"); 302 if (Dict::cast(*kw_args).numItems() != 0) { 303 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 304 thread->stackDrop(has_varkeywords + 2); 305 return result; 306 } 307 } 308 Tuple args(&scope, thread->stackPeek(has_varkeywords)); 309 if (args.length() == 0) { 310 RawObject result = raiseTypeErrorMustBeBound(thread, function); 311 thread->stackDrop(has_varkeywords + 2); 312 return result; 313 } 314 Object self(&scope, args.at(0)); 315 Object varargs(&scope, thread->runtime()->tupleSubseq(thread, args, 1, 316 args.length() - 1)); 317 RawObject result = callMethVarArgs(thread, function, self, varargs); 318 thread->stackDrop(has_varkeywords + 2); 319 return result; 320} 321 322// callMethKeywordArgs 323 324static RawObject callMethKeywords(Thread* thread, const Function& function, 325 const Object& self, const Object& args, 326 const Object& kwargs) { 327 HandleScope scope(thread); 328 Int address(&scope, function.code()); 329 ternaryfunc method = bit_cast<ternaryfunc>(address.asCPtr()); 330 Runtime* runtime = thread->runtime(); 331 PyObject* self_obj = 332 self.isUnbound() ? nullptr : ApiHandle::newReference(runtime, *self); 333 PyObject* args_obj = ApiHandle::newReference(runtime, *args); 334 PyObject* kwargs_obj = nullptr; 335 if (*kwargs != NoneType::object()) { 336 kwargs_obj = ApiHandle::newReference(runtime, *kwargs); 337 } 338 PyObject* pyresult = (*method)(self_obj, args_obj, kwargs_obj); 339 Object result(&scope, ApiHandle::checkFunctionResult(thread, pyresult)); 340 if (self_obj != nullptr) { 341 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 342 } 343 ApiHandle::decref(ApiHandle::fromPyObject(args_obj)); 344 if (kwargs_obj != nullptr) { 345 ApiHandle::decref(ApiHandle::fromPyObject(kwargs_obj)); 346 } 347 return *result; 348} 349 350RawObject methodTrampolineKeywords(Thread* thread, word nargs) { 351 HandleScope scope(thread); 352 Runtime* runtime = thread->runtime(); 353 Function function(&scope, thread->stackPeek(nargs)); 354 if (nargs == 0) { 355 RawObject result = raiseTypeErrorMustBeBound(thread, function); 356 thread->stackDrop(nargs + 1); 357 return result; 358 } 359 Object self(&scope, thread->stackPeek(nargs - 1)); 360 Object varargs_obj(&scope, NoneType::object()); 361 word num_varargs = nargs - 1; 362 if (num_varargs > 0) { 363 MutableTuple varargs(&scope, runtime->newMutableTuple(num_varargs)); 364 for (word i = 0; i < num_varargs; i++) { 365 varargs.atPut(num_varargs - i - 1, thread->stackPeek(i)); 366 } 367 varargs_obj = varargs.becomeImmutable(); 368 } else { 369 varargs_obj = runtime->emptyTuple(); 370 } 371 Object keywords(&scope, NoneType::object()); 372 RawObject result = 373 callMethKeywords(thread, function, self, varargs_obj, keywords); 374 thread->stackDrop(nargs + 1); 375 return result; 376} 377 378RawObject methodTrampolineKeywordsKw(Thread* thread, word nargs) { 379 HandleScope scope(thread); 380 Runtime* runtime = thread->runtime(); 381 Tuple kw_names(&scope, thread->stackPeek(0)); 382 Object kwargs(&scope, NoneType::object()); 383 word num_keywords = kw_names.length(); 384 if (num_keywords != 0) { 385 Dict dict(&scope, runtime->newDict()); 386 for (word i = 0; i < num_keywords; i++) { 387 Str name(&scope, kw_names.at(i)); 388 Object value(&scope, thread->stackPeek(num_keywords - i)); 389 dictAtPutByStr(thread, dict, name, value); 390 } 391 kwargs = *dict; 392 } 393 Function function(&scope, thread->stackPeek(nargs + 1)); 394 if (nargs - num_keywords == 0) { 395 RawObject result = raiseTypeErrorMustBeBound(thread, function); 396 thread->stackDrop(nargs + 2); 397 return result; 398 } 399 word num_positional = nargs - num_keywords - 1; 400 Object args_obj(&scope, NoneType::object()); 401 if (num_positional > 0) { 402 MutableTuple args(&scope, runtime->newMutableTuple(num_positional)); 403 for (word i = 0; i < num_positional; i++) { 404 args.atPut(i, thread->stackPeek(nargs - i - 1)); 405 } 406 args_obj = args.becomeImmutable(); 407 } else { 408 args_obj = runtime->emptyTuple(); 409 } 410 Object self(&scope, thread->stackPeek(nargs)); 411 RawObject result = callMethKeywords(thread, function, self, args_obj, kwargs); 412 thread->stackDrop(nargs + 2); 413 return result; 414} 415 416RawObject methodTrampolineKeywordsEx(Thread* thread, word flags) { 417 HandleScope scope(thread); 418 bool has_varkeywords = flags & CallFunctionExFlag::VAR_KEYWORDS; 419 Tuple varargs(&scope, thread->stackPeek(has_varkeywords)); 420 Object kwargs(&scope, NoneType::object()); 421 if (has_varkeywords) { 422 kwargs = thread->stackTop(); 423 if (!kwargs.isDict()) UNIMPLEMENTED("mapping kwargs"); 424 } 425 Function function(&scope, thread->stackPeek(has_varkeywords + 1)); 426 if (varargs.length() == 0) { 427 RawObject result = raiseTypeErrorMustBeBound(thread, function); 428 thread->stackDrop(has_varkeywords + 2); 429 return result; 430 } 431 Object self(&scope, varargs.at(0)); 432 Object args(&scope, thread->runtime()->tupleSubseq(thread, varargs, 1, 433 varargs.length() - 1)); 434 RawObject result = callMethKeywords(thread, function, self, args, kwargs); 435 thread->stackDrop(has_varkeywords + 2); 436 return result; 437} 438 439static RawObject callMethFast(Thread* thread, const Function& function, 440 const Object& self, PyObject* const* args, 441 word num_args) { 442 _PyCFunctionFast method = 443 bit_cast<_PyCFunctionFast>(Int::cast(function.code()).asCPtr()); 444 PyObject* self_obj = self.isUnbound() 445 ? nullptr 446 : ApiHandle::newReference(thread->runtime(), *self); 447 PyObject* pyresult = (*method)(self_obj, args, num_args); 448 RawObject result = ApiHandle::checkFunctionResult(thread, pyresult); 449 if (self_obj != nullptr) { 450 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 451 } 452 return result; 453} 454 455RawObject methodTrampolineFast(Thread* thread, word nargs) { 456 HandleScope scope(thread); 457 Function function(&scope, thread->stackPeek(nargs)); 458 if (nargs == 0) { 459 RawObject result = raiseTypeErrorMustBeBound(thread, function); 460 thread->stackDrop(nargs + 1); 461 return result; 462 } 463 Object self(&scope, thread->stackPeek(nargs - 1)); 464 word num_positional = nargs - 1; 465 466 PyObject* small_array[kMaxStackArguments] = {}; 467 PyObject** args; 468 if (num_positional <= kMaxStackArguments) { 469 args = small_array; 470 } else { 471 args = reinterpret_cast<PyObject**>( 472 std::malloc(num_positional * sizeof(args[0]))); 473 } 474 Runtime* runtime = thread->runtime(); 475 for (word i = 0; i < num_positional; i++) { 476 args[nargs - i - 2] = 477 ApiHandle::newReference(runtime, thread->stackPeek(i)); 478 } 479 Object result(&scope, 480 callMethFast(thread, function, self, args, num_positional)); 481 for (word i = 0; i < num_positional; i++) { 482 ApiHandle::decref(ApiHandle::fromPyObject(args[nargs - i - 2])); 483 } 484 thread->stackDrop(nargs + 1); 485 if (args != small_array) { 486 std::free(args); 487 } 488 return *result; 489} 490 491RawObject methodTrampolineFastKw(Thread* thread, word nargs) { 492 HandleScope scope(thread); 493 Function function(&scope, thread->stackPeek(nargs + 1)); 494 if (nargs == 0) { 495 RawObject result = raiseTypeErrorMustBeBound(thread, function); 496 thread->stackDrop(nargs + 2); 497 return result; 498 } 499 Tuple kw_names(&scope, thread->stackPeek(0)); 500 if (kw_names.length() != 0) { 501 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 502 thread->stackDrop(nargs + 2); 503 return result; 504 } 505 Object self(&scope, thread->stackPeek(nargs)); 506 word num_positional = nargs - 1; 507 508 PyObject* small_array[kMaxStackArguments] = {}; 509 PyObject** args; 510 if (num_positional <= kMaxStackArguments) { 511 args = small_array; 512 } else { 513 args = reinterpret_cast<PyObject**>( 514 std::malloc(num_positional * sizeof(args[0]))); 515 } 516 Runtime* runtime = thread->runtime(); 517 for (word i = 0; i < num_positional; i++) { 518 args[i] = 519 ApiHandle::newReference(runtime, thread->stackPeek(nargs - i - 1)); 520 } 521 Object result(&scope, callMethFast(thread, function, self, args, nargs - 1)); 522 for (word i = 0; i < num_positional; i++) { 523 ApiHandle::decref(ApiHandle::fromPyObject(args[i])); 524 } 525 thread->stackDrop(nargs + 2); 526 if (args != small_array) { 527 std::free(args); 528 } 529 return *result; 530} 531 532RawObject methodTrampolineFastEx(Thread* thread, word flags) { 533 HandleScope scope(thread); 534 bool has_varkeywords = flags & CallFunctionExFlag::VAR_KEYWORDS; 535 Function function(&scope, thread->stackPeek(has_varkeywords + 1)); 536 537 // Get the keyword arguments 538 if (has_varkeywords) { 539 Object kw_args_obj(&scope, thread->stackTop()); 540 if (!kw_args_obj.isDict()) UNIMPLEMENTED("mapping kwargs"); 541 Dict kw_args(&scope, *kw_args_obj); 542 if (kw_args.numItems() != 0) { 543 RawObject result = raiseTypeErrorNoKeywordArguments(thread, function); 544 thread->stackDrop(has_varkeywords + 2); 545 return result; 546 } 547 } 548 549 Tuple args_tuple(&scope, thread->stackPeek(has_varkeywords)); 550 word args_length = args_tuple.length(); 551 if (args_length == 0) { 552 RawObject result = raiseTypeErrorMustBeBound(thread, function); 553 thread->stackDrop(has_varkeywords + 2); 554 return result; 555 } 556 Object self(&scope, args_tuple.at(0)); 557 word num_positional = args_length - 1; 558 559 PyObject* small_array[kMaxStackArguments] = {}; 560 PyObject** args; 561 if (num_positional <= kMaxStackArguments) { 562 args = small_array; 563 } else { 564 args = reinterpret_cast<PyObject**>( 565 std::malloc(num_positional * sizeof(args[0]))); 566 } 567 568 // Set the positional arguments 569 Runtime* runtime = thread->runtime(); 570 for (word i = 0; i < num_positional; i++) { 571 args[i] = ApiHandle::newReference(runtime, args_tuple.at(i + 1)); 572 } 573 574 Object result(&scope, 575 callMethFast(thread, function, self, args, num_positional)); 576 for (word i = 0; i < num_positional; i++) { 577 ApiHandle::decref(ApiHandle::fromPyObject(args[i])); 578 } 579 thread->stackDrop(has_varkeywords + 2); 580 if (args != small_array) { 581 std::free(args); 582 } 583 return *result; 584} 585 586static RawObject callMethFastWithKeywordsWithKwargs( 587 Thread* thread, const Function& function, const Object& self, 588 PyObject* const* args, word num_args, const Object& kw_names) { 589 _PyCFunctionFastWithKeywords method = bit_cast<_PyCFunctionFastWithKeywords>( 590 Int::cast(function.code()).asCPtr()); 591 Runtime* runtime = thread->runtime(); 592 PyObject* self_obj = 593 self.isUnbound() ? nullptr : ApiHandle::newReference(runtime, *self); 594 ApiHandle* kw_names_obj = ApiHandle::newReference(runtime, *kw_names); 595 PyObject* pyresult = (*method)(self_obj, args, num_args, kw_names_obj); 596 RawObject result = ApiHandle::checkFunctionResult(thread, pyresult); 597 ApiHandle::decref(kw_names_obj); 598 if (self_obj != nullptr) { 599 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 600 } 601 return result; 602} 603 604static RawObject callMethFastWithKeywords(Thread* thread, 605 const Function& function, 606 const Object& self, 607 PyObject* const* args, 608 word num_args) { 609 _PyCFunctionFastWithKeywords method = bit_cast<_PyCFunctionFastWithKeywords>( 610 Int::cast(function.code()).asCPtr()); 611 PyObject* self_obj = self.isUnbound() 612 ? nullptr 613 : ApiHandle::newReference(thread->runtime(), *self); 614 PyObject* pyresult = (*method)(self_obj, args, num_args, nullptr); 615 RawObject result = ApiHandle::checkFunctionResult(thread, pyresult); 616 if (self_obj != nullptr) { 617 ApiHandle::decref(ApiHandle::fromPyObject(self_obj)); 618 } 619 return result; 620} 621 622RawObject methodTrampolineFastWithKeywords(Thread* thread, word nargs) { 623 HandleScope scope(thread); 624 Function function(&scope, thread->stackPeek(nargs)); 625 if (nargs == 0) { 626 RawObject result = raiseTypeErrorMustBeBound(thread, function); 627 thread->stackDrop(nargs + 1); 628 return result; 629 } 630 Object self(&scope, thread->stackPeek(nargs - 1)); 631 632 std::unique_ptr<PyObject*[]> fastcall_args(new PyObject*[nargs - 1]); 633 Runtime* runtime = thread->runtime(); 634 for (word i = 0; i < nargs - 1; i++) { 635 fastcall_args[nargs - i - 2] = 636 ApiHandle::newReference(runtime, thread->stackPeek(i)); 637 } 638 word num_positional = nargs - 1; 639 Object result(&scope, 640 callMethFastWithKeywords(thread, function, self, 641 fastcall_args.get(), num_positional)); 642 for (word i = 0; i < nargs - 1; i++) { 643 ApiHandle::decref(ApiHandle::fromPyObject(fastcall_args[nargs - i - 2])); 644 } 645 thread->stackDrop(nargs + 1); 646 return *result; 647} 648 649RawObject methodTrampolineFastWithKeywordsKw(Thread* thread, word nargs) { 650 HandleScope scope(thread); 651 Function function(&scope, thread->stackPeek(nargs + 1)); 652 if (nargs == 0) { 653 RawObject result = raiseTypeErrorMustBeBound(thread, function); 654 thread->stackDrop(nargs + 2); 655 return result; 656 } 657 Object self(&scope, thread->stackPeek(nargs)); 658 659 std::unique_ptr<PyObject*[]> fastcall_args(new PyObject*[nargs - 1]); 660 Runtime* runtime = thread->runtime(); 661 for (word i = 0; i < nargs - 1; i++) { 662 fastcall_args[i] = 663 ApiHandle::newReference(runtime, thread->stackPeek(nargs - i - 1)); 664 } 665 Tuple kw_names(&scope, thread->stackPeek(0)); 666 word num_positional = nargs - kw_names.length() - 1; 667 Object result(&scope, callMethFastWithKeywordsWithKwargs( 668 thread, function, self, fastcall_args.get(), 669 num_positional, kw_names)); 670 for (word i = 0; i < nargs - 1; i++) { 671 ApiHandle::decref(ApiHandle::fromPyObject(fastcall_args[i])); 672 } 673 thread->stackDrop(nargs + 2); 674 return *result; 675} 676 677RawObject methodTrampolineFastWithKeywordsEx(Thread* thread, word flags) { 678 HandleScope scope(thread); 679 Runtime* runtime = thread->runtime(); 680 bool has_varkeywords = flags & CallFunctionExFlag::VAR_KEYWORDS; 681 word num_keywords = 0; 682 683 // Get the keyword arguments 684 if (has_varkeywords) { 685 Object kw_args_obj(&scope, thread->stackTop()); 686 if (!kw_args_obj.isDict()) UNIMPLEMENTED("mapping kwargs"); 687 Dict kw_args(&scope, *kw_args_obj); 688 num_keywords = kw_args.numItems(); 689 } 690 691 Function function(&scope, thread->stackPeek(has_varkeywords + 1)); 692 Tuple args(&scope, thread->stackPeek(has_varkeywords)); 693 word args_length = args.length(); 694 if (args_length == 0) { 695 RawObject result = raiseTypeErrorMustBeBound(thread, function); 696 thread->stackDrop(has_varkeywords + 2); 697 return result; 698 } 699 Object self(&scope, args.at(0)); 700 word num_positional = args_length - 1; 701 std::unique_ptr<PyObject*[]> fastcall_args( 702 new PyObject*[num_positional + num_keywords]); 703 704 // Set the positional arguments 705 for (word i = 0; i < num_positional; i++) { 706 fastcall_args[i] = ApiHandle::newReference(runtime, args.at(i + 1)); 707 } 708 709 // Set the keyword arguments 710 Tuple kw_names(&scope, runtime->emptyTuple()); 711 if (has_varkeywords) { 712 Dict kw_args(&scope, thread->stackTop()); 713 714 if (num_keywords > 0) { 715 Object key(&scope, NoneType::object()); 716 Object value(&scope, NoneType::object()); 717 kw_names = runtime->newMutableTuple(num_keywords); 718 for (word dict_i = 0, arg_i = 0; 719 dictNextItem(kw_args, &dict_i, &key, &value); arg_i++) { 720 MutableTuple::cast(*kw_names).atPut(arg_i, *key); 721 fastcall_args[num_positional + arg_i] = 722 ApiHandle::newReference(runtime, *value); 723 } 724 MutableTuple::cast(*kw_names).becomeImmutable(); 725 } 726 } 727 728 Object result(&scope, NoneType::object()); 729 if (!has_varkeywords) { 730 result = callMethFastWithKeywords(thread, function, self, 731 fastcall_args.get(), num_positional); 732 } else { 733 result = callMethFastWithKeywordsWithKwargs( 734 thread, function, self, fastcall_args.get(), num_positional, kw_names); 735 } 736 for (word i = 0; i < num_positional + num_keywords; i++) { 737 ApiHandle::decref(ApiHandle::fromPyObject(fastcall_args[i])); 738 } 739 thread->stackDrop(has_varkeywords + 2); 740 return *result; 741} 742 743} // namespace py