this repo has no description
at trunk 742 lines 29 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "trampolines.h" 3 4#include "dict-builtins.h" 5#include "frame.h" 6#include "globals.h" 7#include "handles.h" 8#include "interpreter.h" 9#include "objects.h" 10#include "runtime.h" 11#include "str-builtins.h" 12#include "thread.h" 13#include "tuple-builtins.h" 14 15namespace py { 16 17// Populate the free variable and cell variable arguments. 18void processFreevarsAndCellvars(Thread* thread, Frame* frame) { 19 // initialize cell variables 20 HandleScope scope(thread); 21 Function function(&scope, frame->function()); 22 DCHECK(function.hasFreevarsOrCellvars(), 23 "no free variables or cell variables"); 24 Code code(&scope, function.code()); 25 Runtime* runtime = thread->runtime(); 26 word num_locals = code.nlocals(); 27 word num_cellvars = code.numCellvars(); 28 for (word i = 0; i < code.numCellvars(); i++) { 29 Cell cell(&scope, runtime->newCell()); 30 31 // Allocate a cell for a local variable if cell2arg is not preset 32 if (code.cell2arg().isNoneType()) { 33 frame->setLocal(num_locals + i, *cell); 34 continue; 35 } 36 37 // Allocate a cell for a local variable if cell2arg is present but 38 // the cell does not match any argument 39 Object arg_index(&scope, Tuple::cast(code.cell2arg()).at(i)); 40 if (arg_index.isNoneType()) { 41 frame->setLocal(num_locals + i, *cell); 42 continue; 43 } 44 45 // Allocate a cell for an argument 46 word local_idx = Int::cast(*arg_index).asWord(); 47 cell.setValue(frame->local(local_idx)); 48 frame->setLocal(local_idx, NoneType::object()); 49 frame->setLocal(num_locals + i, *cell); 50 } 51 52 // initialize free variables 53 DCHECK(code.numFreevars() == 0 || 54 code.numFreevars() == Tuple::cast(function.closure()).length(), 55 "Number of freevars is different than the closure."); 56 for (word i = 0; i < code.numFreevars(); i++) { 57 frame->setLocal(num_locals + num_cellvars + i, 58 Tuple::cast(function.closure()).at(i)); 59 } 60} 61 62RawObject raiseMissingArgumentsError(Thread* thread, word nargs, 63 RawFunction function) { 64 HandleScope scope(thread); 65 Function function_obj(&scope, function); 66 Object defaults(&scope, function_obj.defaults()); 67 word n_defaults = defaults.isNoneType() ? 0 : Tuple::cast(*defaults).length(); 68 return thread->raiseWithFmt( 69 LayoutId::kTypeError, 70 "'%F' takes min %w positional arguments but %w given", &function_obj, 71 function_obj.argcount() - n_defaults, nargs); 72} 73 74RawObject processDefaultArguments(Thread* thread, word nargs, 75 RawFunction function_raw) { 76 word argcount = function_raw.argcount(); 77 word n_missing_args = argcount - nargs; 78 if (n_missing_args > 0) { 79 RawObject result = 80 addDefaultArguments(thread, nargs, function_raw, n_missing_args); 81 if (result.isErrorException()) return result; 82 function_raw = Function::cast(result); 83 nargs += n_missing_args; 84 if (function_raw.hasSimpleCall()) { 85 DCHECK(function_raw.totalArgs() == nargs, "argument count mismatch"); 86 return function_raw; 87 } 88 } 89 90 HandleScope scope(thread); 91 Runtime* runtime = thread->runtime(); 92 Function function(&scope, function_raw); 93 Object varargs_param(&scope, runtime->emptyTuple()); 94 if (n_missing_args < 0) { 95 // We have too many arguments. 96 if (!function.hasVarargs()) { 97 thread->stackDrop(nargs + 1); 98 return thread->raiseWithFmt( 99 LayoutId::kTypeError, 100 "'%F' takes max %w positional arguments but %w given", &function, 101 argcount, nargs); 102 } 103 // Put extra positional args into the varargs tuple. 104 word len = -n_missing_args; 105 MutableTuple tuple(&scope, runtime->newMutableTuple(len)); 106 for (word i = (len - 1); i >= 0; i--) { 107 tuple.atPut(i, thread->stackPop()); 108 } 109 nargs -= len; 110 varargs_param = tuple.becomeImmutable(); 111 } 112 113 // If there are any keyword-only args, there must be defaults for them 114 // because we arrived here via CALL_FUNCTION (and thus, no keywords were 115 // supplied at the call site). 116 Code code(&scope, function.code()); 117 word kwonlyargcount = code.kwonlyargcount(); 118 if (kwonlyargcount > 0) { 119 if (function.kwDefaults().isNoneType()) { 120 thread->stackDrop(nargs + 1); 121 return thread->raiseWithFmt(LayoutId::kTypeError, 122 "missing keyword-only argument"); 123 } 124 Dict kw_defaults(&scope, function.kwDefaults()); 125 Tuple formal_names(&scope, code.varnames()); 126 word first_kw = argcount; 127 Object name(&scope, NoneType::object()); 128 for (word i = 0; i < kwonlyargcount; i++) { 129 name = formal_names.at(first_kw + i); 130 RawObject value = dictAtByStr(thread, kw_defaults, name); 131 if (value.isErrorNotFound()) { 132 thread->stackDrop(nargs + i + 1); 133 return thread->raiseWithFmt(LayoutId::kTypeError, 134 "missing keyword-only argument"); 135 } 136 thread->stackPush(value); 137 } 138 nargs += kwonlyargcount; 139 } 140 141 if (function.hasVarargs()) { 142 thread->stackPush(*varargs_param); 143 nargs++; 144 } 145 if (function.hasVarkeyargs()) { 146 // VARKEYARGS - because we arrived via CALL_FUNCTION, no keyword arguments 147 // provided. Just add an empty dict. 148 thread->stackPush(runtime->newDict()); 149 nargs++; 150 } 151 DCHECK(function.totalArgs() == nargs, "argument count mismatch"); 152 return *function; 153} 154 155// Verify correct number and order of arguments. If order is wrong, try to 156// fix it. If argument is missing (denoted by Error::object()), try to supply 157// it with a default. This routine expects the number of args on the stack 158// and number of names in the actual_names tuple to match. Caller must pad 159// prior to calling to ensure this. 160// Return None::object() if successful, error object if not. 161static RawObject checkArgs(Thread* thread, const Function& function, 162 RawObject* kw_arg_base, const Tuple& actual_names, 163 const Tuple& formal_names, word start) { 164 word posonlyargcount = RawCode::cast(function.code()).posonlyargcount(); 165 word num_actuals = actual_names.length(); 166 // Helper function to swap actual arguments and names 167 auto swap = [&kw_arg_base](RawMutableTuple ordered_names, word arg_pos1, 168 word arg_pos2) -> void { 169 RawObject tmp = *(kw_arg_base - arg_pos1); 170 *(kw_arg_base - arg_pos1) = *(kw_arg_base - arg_pos2); 171 *(kw_arg_base - arg_pos2) = tmp; 172 tmp = ordered_names.at(arg_pos1); 173 ordered_names.atPut(arg_pos1, ordered_names.at(arg_pos2)); 174 ordered_names.atPut(arg_pos2, tmp); 175 }; 176 // Helper function to retrieve argument 177 auto arg_at = [&kw_arg_base](word idx) -> RawObject& { 178 return *(kw_arg_base - idx); 179 }; 180 HandleScope scope(thread); 181 // In case the order of the parameters in the call does not match the 182 // declaration order, create a copy of `actual_names` to adjust it to match 183 // `formal_names`. 184 Tuple ordered_names(&scope, *actual_names); 185 Object formal_name(&scope, NoneType::object()); 186 for (word arg_pos = 0; arg_pos < num_actuals; arg_pos++) { 187 word formal_pos = arg_pos + start; 188 formal_name = formal_names.at(formal_pos); 189 RawObject result = 190 Runtime::objectEquals(thread, ordered_names.at(arg_pos), *formal_name); 191 if (result.isErrorException()) return result; 192 if (result == Bool::trueObj()) { 193 if (formal_pos >= posonlyargcount) { 194 // We're good here: actual & formal arg names match. Check the next 195 // one. 196 continue; 197 } 198 // A matching keyword arg but for a positional-only parameter. 199 return Thread::current()->raiseWithFmt( 200 LayoutId::kTypeError, 201 "keyword argument specified for positional-only argument '%S'", 202 &formal_name); 203 } 204 // Mismatch. Try to fix it. Note: args grow down. 205 // TODO(T66307914): Avoid heap allocation here. 206 // In case `actual_names` needs to be adjusted, create a copy to avoid 207 // modifying `actual_names`. 208 if (ordered_names == actual_names) { 209 word actual_names_length = actual_names.length(); 210 ordered_names = thread->runtime()->newMutableTuple(actual_names_length); 211 for (word i = 0; i < actual_names_length; ++i) { 212 ordered_names.atPut(i, actual_names.at(i)); 213 } 214 } 215 DCHECK(ordered_names.isMutableTuple(), "MutableTuple is expected"); 216 bool swapped = false; 217 // Look for expected Formal name in Actuals tuple. 218 for (word i = arg_pos + 1; i < num_actuals; i++) { 219 result = Runtime::objectEquals(thread, ordered_names.at(i), *formal_name); 220 if (result.isErrorException()) return result; 221 if (result == Bool::trueObj()) { 222 // Found it. Swap both the stack and the ordered_names tuple. 223 swap(MutableTuple::cast(*ordered_names), arg_pos, i); 224 swapped = true; 225 break; 226 } 227 } 228 if (swapped) { 229 // We managed to fix it. Check the next one. 230 continue; 231 } 232 // Can't find an Actual for this Formal. 233 // If we have a real actual in current slot, move it somewhere safe. 234 if (!arg_at(arg_pos).isError()) { 235 for (word i = arg_pos + 1; i < num_actuals; i++) { 236 if (arg_at(i).isError()) { 237 // Found an uninitialized slot. Use it to save current actual. 238 swap(MutableTuple::cast(*ordered_names), arg_pos, i); 239 break; 240 } 241 } 242 // If we were unable to find a slot to swap into, TypeError 243 if (!arg_at(arg_pos).isError()) { 244 Object param_name(&scope, swapped ? formal_names.at(arg_pos) 245 : ordered_names.at(arg_pos)); 246 return thread->raiseWithFmt( 247 LayoutId::kTypeError, 248 "%F() got an unexpected keyword argument '%S'", &function, 249 &param_name); 250 } 251 } 252 // Now, can we fill that slot with a default argument? 253 word absolute_pos = arg_pos + start; 254 word argcount = function.argcount(); 255 if (absolute_pos < argcount) { 256 word defaults_size = function.hasDefaults() 257 ? Tuple::cast(function.defaults()).length() 258 : 0; 259 word defaults_start = argcount - defaults_size; 260 if (absolute_pos >= (defaults_start)) { 261 // Set the default value 262 Tuple default_args(&scope, function.defaults()); 263 *(kw_arg_base - arg_pos) = 264 default_args.at(absolute_pos - defaults_start); 265 continue; // Got it, move on to the next 266 } 267 } else if (!function.kwDefaults().isNoneType()) { 268 // How about a kwonly default? 269 Dict kw_defaults(&scope, function.kwDefaults()); 270 Str name(&scope, formal_names.at(arg_pos + start)); 271 RawObject val = dictAtByStr(thread, kw_defaults, name); 272 if (!val.isErrorNotFound()) { 273 *(kw_arg_base - arg_pos) = val; 274 continue; // Got it, move on to the next 275 } 276 } 277 return thread->raiseWithFmt(LayoutId::kTypeError, "missing argument"); 278 } 279 return NoneType::object(); 280} 281 282static word findName(Thread* thread, word posonlyargcount, const Object& name, 283 const Tuple& names) { 284 word len = names.length(); 285 for (word i = posonlyargcount; i < len; i++) { 286 RawObject result = Runtime::objectEquals(thread, *name, names.at(i)); 287 if (result.isErrorException()) return -1; 288 if (result == Bool::trueObj()) { 289 return i; 290 } 291 } 292 return len; 293} 294 295// Converts the outgoing arguments of a keyword call into positional arguments 296// and processes default arguments, rearranging everything into a form expected 297// by the callee. 298RawObject prepareKeywordCall(Thread* thread, word nargs, 299 RawFunction function_raw) { 300 HandleScope scope(thread); 301 Function function(&scope, function_raw); 302 // Pop the tuple of kwarg names 303 Tuple keywords(&scope, thread->stackPop()); 304 Code code(&scope, function.code()); 305 word expected_args = function.argcount() + code.kwonlyargcount(); 306 word num_keyword_args = keywords.length(); 307 word num_positional_args = nargs - num_keyword_args; 308 Tuple varnames(&scope, code.varnames()); 309 Object tmp_varargs(&scope, NoneType::object()); 310 Object tmp_dict(&scope, NoneType::object()); 311 312 // We expect use of keyword argument calls to be uncommon, but when used 313 // we anticipate mostly use of simple forms. General scheme here is to 314 // normalize the odd forms into standard form and then handle them all 315 // in the same place. 316 if (function.hasVarargsOrVarkeyargs()) { 317 Runtime* runtime = thread->runtime(); 318 if (function.hasVarargs()) { 319 // If we have more positional than expected, add the remainder to a tuple, 320 // remove from the stack and close up the hole. 321 word excess = num_positional_args - function.argcount(); 322 if (excess > 0) { 323 MutableTuple varargs(&scope, runtime->newMutableTuple(excess)); 324 // Point to the leftmost excess argument 325 RawObject* p = (thread->stackPointer() + num_keyword_args + excess) - 1; 326 // Copy the excess to the * tuple 327 for (word i = 0; i < excess; i++) { 328 varargs.atPut(i, *(p - i)); 329 } 330 // Fill in the hole 331 for (word i = 0; i < num_keyword_args; i++) { 332 *p = *(p - excess); 333 p--; 334 } 335 // Adjust the counts 336 thread->stackDrop(excess); 337 nargs -= excess; 338 num_positional_args -= excess; 339 tmp_varargs = varargs.becomeImmutable(); 340 } else { 341 tmp_varargs = runtime->emptyTuple(); 342 } 343 } 344 if (function.hasVarkeyargs()) { 345 // Too many positional args passed? 346 if (num_positional_args > function.argcount()) { 347 thread->stackDrop(nargs + 1); 348 return thread->raiseWithFmt(LayoutId::kTypeError, 349 "Too many positional arguments"); 350 } 351 // If we have keyword arguments that don't appear in the formal parameter 352 // list, add them to a keyword dict. 353 Dict dict(&scope, runtime->newDict()); 354 List saved_keyword_list(&scope, runtime->newList()); 355 List saved_values(&scope, runtime->newList()); 356 DCHECK(varnames.length() >= expected_args, 357 "varnames must be greater than or equal to positional args"); 358 RawObject* p = thread->stackPointer() + (num_keyword_args - 1); 359 word posonlyargcount = code.posonlyargcount(); 360 for (word i = 0; i < num_keyword_args; i++) { 361 Object key(&scope, keywords.at(i)); 362 Object value(&scope, *(p - i)); 363 word result = findName(thread, posonlyargcount, key, varnames); 364 if (result < 0) { 365 thread->stackDrop(nargs + 1); 366 return Error::exception(); 367 } 368 if (result < expected_args) { 369 // Got a match, stash pair for future restoration on the stack 370 runtime->listAdd(thread, saved_keyword_list, key); 371 runtime->listAdd(thread, saved_values, value); 372 } else { 373 // New, add it and associated value to the varkeyargs dict 374 Object hash_obj(&scope, Interpreter::hash(thread, key)); 375 if (hash_obj.isErrorException()) { 376 thread->stackDrop(nargs + 1); 377 return *hash_obj; 378 } 379 word hash = SmallInt::cast(*hash_obj).value(); 380 Object dict_result(&scope, dictAtPut(thread, dict, key, hash, value)); 381 if (dict_result.isErrorException()) { 382 thread->stackDrop(nargs + 1); 383 return *dict_result; 384 } 385 nargs--; 386 } 387 } 388 // Now, restore the stashed values to the stack and build a new 389 // keywords name list. 390 thread->stackDrop(num_keyword_args); // Pop all of the old keyword values 391 num_keyword_args = saved_keyword_list.numItems(); 392 // Replace the old keywords list with a new one. 393 if (num_keyword_args > 0) { 394 MutableTuple new_keywords(&scope, 395 runtime->newMutableTuple(num_keyword_args)); 396 for (word i = 0; i < num_keyword_args; i++) { 397 thread->stackPush(saved_values.at(i)); 398 new_keywords.atPut(i, saved_keyword_list.at(i)); 399 } 400 keywords = new_keywords.becomeImmutable(); 401 } else { 402 keywords = runtime->emptyTuple(); 403 } 404 tmp_dict = *dict; 405 } 406 } 407 // At this point, all vararg forms have been normalized 408 RawObject* kw_arg_base = (thread->stackPointer() + num_keyword_args) - 409 1; // pointer to first non-positional arg 410 if (UNLIKELY(nargs > expected_args)) { 411 thread->stackDrop(nargs + 1); 412 return thread->raiseWithFmt(LayoutId::kTypeError, "Too many arguments"); 413 } 414 if (UNLIKELY(nargs < expected_args)) { 415 // Too few args passed. Can we supply default args to make it work? 416 // First, normalize & pad keywords and stack arguments 417 word name_tuple_size = expected_args - num_positional_args; 418 MutableTuple padded_keywords( 419 &scope, thread->runtime()->newMutableTuple(name_tuple_size)); 420 padded_keywords.replaceFromWith(0, *keywords, num_keyword_args); 421 // Fill in missing spots w/ Error code 422 for (word i = num_keyword_args; i < name_tuple_size; i++) { 423 thread->stackPush(Error::error()); 424 nargs++; 425 padded_keywords.atPut(i, Error::error()); 426 } 427 keywords = padded_keywords.becomeImmutable(); 428 } 429 // Now we've got the right number. Do they match up? 430 RawObject res = checkArgs(thread, function, kw_arg_base, keywords, varnames, 431 num_positional_args); 432 if (res.isErrorException()) { 433 thread->stackDrop(nargs + 1); 434 return res; // TypeError created by checkArgs. 435 } 436 CHECK(res.isNoneType(), "checkArgs should return an Error or None"); 437 // If we're a vararg form, need to push the tuple/dict. 438 if (function.hasVarargs()) { 439 thread->stackPush(*tmp_varargs); 440 nargs++; 441 } 442 if (function.hasVarkeyargs()) { 443 thread->stackPush(*tmp_dict); 444 nargs++; 445 } 446 DCHECK(function.totalArgs() == nargs, "argument count mismatch"); 447 return *function; 448} 449 450// Converts explode arguments into positional arguments. 451// 452// Returns the new number of positional arguments as a SmallInt, or Error if an 453// exception was raised (most likely due to a non-string keyword name). 454static RawObject processExplodeArguments(Thread* thread, word flags) { 455 HandleScope scope(thread); 456 Object kw_mapping(&scope, NoneType::object()); 457 if (flags & CallFunctionExFlag::VAR_KEYWORDS) { 458 kw_mapping = thread->stackPop(); 459 } 460 Tuple positional_args(&scope, thread->stackPop()); 461 word length = positional_args.length(); 462 for (word i = 0; i < length; i++) { 463 thread->stackPush(positional_args.at(i)); 464 } 465 word nargs = length; 466 Runtime* runtime = thread->runtime(); 467 if (flags & CallFunctionExFlag::VAR_KEYWORDS) { 468 if (!kw_mapping.isDict()) { 469 DCHECK(runtime->isMapping(thread, kw_mapping), 470 "kw_mapping must have __getitem__"); 471 Dict dict(&scope, runtime->newDict()); 472 Object result(&scope, dictMergeIgnore(thread, dict, kw_mapping)); 473 if (result.isErrorException()) { 474 thread->stackDrop(nargs + 1); 475 if (thread->pendingExceptionType() == 476 runtime->typeAt(LayoutId::kAttributeError)) { 477 thread->clearPendingException(); 478 return thread->raiseWithFmt(LayoutId::kTypeError, 479 "argument must be a mapping, not %T\n", 480 &kw_mapping); 481 } 482 return *result; 483 } 484 kw_mapping = *dict; 485 } 486 Dict dict(&scope, *kw_mapping); 487 word len = dict.numItems(); 488 if (len == 0) { 489 thread->stackPush(runtime->emptyTuple()); 490 return SmallInt::fromWord(nargs); 491 } 492 MutableTuple keys(&scope, runtime->newMutableTuple(len)); 493 Object key(&scope, NoneType::object()); 494 Object value(&scope, NoneType::object()); 495 for (word i = 0, j = 0; dictNextItem(dict, &i, &key, &value); j++) { 496 if (!runtime->isInstanceOfStr(*key)) { 497 thread->stackDrop(nargs + 1); 498 return thread->raiseWithFmt(LayoutId::kTypeError, 499 "keywords must be strings"); 500 } 501 keys.atPut(j, *key); 502 thread->stackPush(*value); 503 nargs++; 504 } 505 thread->stackPush(keys.becomeImmutable()); 506 } 507 return SmallInt::fromWord(nargs); 508} 509 510// Takes the outgoing arguments of an explode argument call and rearranges them 511// into the form expected by the callee. 512RawObject prepareExplodeCall(Thread* thread, word flags, 513 RawFunction function_raw) { 514 HandleScope scope(thread); 515 Function function(&scope, function_raw); 516 517 RawObject arg_obj = processExplodeArguments(thread, flags); 518 if (arg_obj.isErrorException()) return arg_obj; 519 word new_argc = SmallInt::cast(arg_obj).value(); 520 521 if (flags & CallFunctionExFlag::VAR_KEYWORDS) { 522 RawObject result = prepareKeywordCall(thread, new_argc, *function); 523 if (result.isErrorException()) { 524 return result; 525 } 526 } else { 527 // Are we one of the less common cases? 528 if (new_argc != function.argcount() || !(function.hasSimpleCall())) { 529 RawObject result = processDefaultArguments(thread, new_argc, *function); 530 if (result.isErrorException()) { 531 return result; 532 } 533 } 534 } 535 return *function; 536} 537 538static RawObject createGeneratorObject(Thread* thread, 539 const Function& function) { 540 Runtime* runtime = thread->runtime(); 541 if (function.isGenerator()) return runtime->newGenerator(); 542 if (function.isCoroutine()) return runtime->newCoroutine(); 543 DCHECK(function.isAsyncGenerator(), "unexpected type"); 544 HandleScope scope(thread); 545 Layout async_gen_layout(&scope, runtime->layoutAt(LayoutId::kAsyncGenerator)); 546 AsyncGenerator async_gen(&scope, runtime->newInstance(async_gen_layout)); 547 async_gen.setFinalizer(NoneType::object()); 548 async_gen.setHooksInited(false); 549 return *async_gen; 550} 551 552static RawObject createGenerator(Thread* thread, const Function& function) { 553 Runtime* runtime = thread->runtime(); 554 HandleScope scope(thread); 555 GeneratorFrame generator_frame(&scope, runtime->newGeneratorFrame(function)); 556 thread->currentFrame()->addReturnMode(Frame::kExitRecursiveInterpreter); 557 thread->popFrameToGeneratorFrame(generator_frame); 558 GeneratorBase gen_base(&scope, createGeneratorObject(thread, function)); 559 gen_base.setGeneratorFrame(*generator_frame); 560 gen_base.setExceptionState(runtime->newExceptionState()); 561 gen_base.setQualname(function.qualname()); 562 gen_base.setName(function.name()); 563 return *gen_base; 564} 565 566RawObject generatorTrampoline(Thread* thread, word nargs) { 567 HandleScope scope(thread); 568 Function function(&scope, thread->stackPeek(nargs)); 569 RawObject error = preparePositionalCall(thread, nargs, *function); 570 if (error.isErrorException()) { 571 return error; 572 } 573 Frame* callee_frame = thread->pushCallFrame(*function); 574 if (UNLIKELY(callee_frame == nullptr)) { 575 thread->stackDrop(nargs + 1); 576 return Error::exception(); 577 } 578 if (function.hasFreevarsOrCellvars()) { 579 processFreevarsAndCellvars(thread, callee_frame); 580 } 581 return createGenerator(thread, function); 582} 583 584RawObject generatorTrampolineKw(Thread* thread, word nargs) { 585 HandleScope scope(thread); 586 // The argument does not include the hidden keyword dictionary argument. Add 587 // one to skip over the keyword dictionary to read the function object. 588 Function function(&scope, thread->stackPeek(nargs + 1)); 589 RawObject error = prepareKeywordCall(thread, nargs, *function); 590 if (error.isErrorException()) { 591 return error; 592 } 593 Frame* callee_frame = thread->pushCallFrame(*function); 594 if (UNLIKELY(callee_frame == nullptr)) { 595 thread->stackDrop(nargs + 1); 596 return Error::exception(); 597 } 598 if (function.hasFreevarsOrCellvars()) { 599 processFreevarsAndCellvars(thread, callee_frame); 600 } 601 return createGenerator(thread, function); 602} 603 604RawObject generatorTrampolineEx(Thread* thread, word flags) { 605 HandleScope scope(thread); 606 // The argument is either zero when there is one argument and one when there 607 // are two arguments. Skip over these arguments to read the function object. 608 word function_offset = (flags & CallFunctionExFlag::VAR_KEYWORDS) ? 2 : 1; 609 Function function(&scope, thread->stackPeek(function_offset)); 610 RawObject error = prepareExplodeCall(thread, flags, *function); 611 if (error.isErrorException()) { 612 return error; 613 } 614 Frame* callee_frame = thread->pushCallFrame(*function); 615 if (UNLIKELY(callee_frame == nullptr)) { 616 thread->stackDrop(function_offset + 1); 617 return Error::exception(); 618 } 619 if (function.hasFreevarsOrCellvars()) { 620 processFreevarsAndCellvars(thread, callee_frame); 621 } 622 return createGenerator(thread, function); 623} 624 625RawObject interpreterTrampoline(Thread* thread, word nargs) { 626 HandleScope scope(thread); 627 Function function(&scope, thread->stackPeek(nargs)); 628 RawObject error = preparePositionalCall(thread, nargs, *function); 629 if (error.isErrorException()) { 630 return error; 631 } 632 Frame* callee_frame = thread->pushCallFrame(*function); 633 if (UNLIKELY(callee_frame == nullptr)) { 634 thread->stackDrop(nargs + 1); 635 return Error::exception(); 636 } 637 if (function.hasFreevarsOrCellvars()) { 638 processFreevarsAndCellvars(thread, callee_frame); 639 } 640 return Interpreter::execute(thread); 641} 642 643RawObject interpreterTrampolineKw(Thread* thread, word nargs) { 644 HandleScope scope(thread); 645 // The argument does not include the hidden keyword dictionary argument. Add 646 // one to skip the keyword dictionary to get to the function object. 647 Function function(&scope, thread->stackPeek(nargs + 1)); 648 RawObject error = prepareKeywordCall(thread, nargs, *function); 649 if (error.isErrorException()) { 650 return error; 651 } 652 Frame* callee_frame = thread->pushCallFrame(*function); 653 if (UNLIKELY(callee_frame == nullptr)) { 654 thread->stackDrop(nargs + 2); 655 return Error::exception(); 656 } 657 if (function.hasFreevarsOrCellvars()) { 658 processFreevarsAndCellvars(thread, callee_frame); 659 } 660 return Interpreter::execute(thread); 661} 662 663RawObject interpreterTrampolineEx(Thread* thread, word flags) { 664 HandleScope scope(thread); 665 // The argument is either zero when there is one argument and one when there 666 // are two arguments. Skip over these arguments to read the function object. 667 word function_offset = (flags & CallFunctionExFlag::VAR_KEYWORDS) ? 2 : 1; 668 Function function(&scope, thread->stackPeek(function_offset)); 669 RawObject error = prepareExplodeCall(thread, flags, *function); 670 if (error.isErrorException()) { 671 return error; 672 } 673 Frame* callee_frame = thread->pushCallFrame(*function); 674 if (UNLIKELY(callee_frame == nullptr)) { 675 thread->stackDrop(function_offset + 1); 676 return Error::exception(); 677 } 678 if (function.hasFreevarsOrCellvars()) { 679 processFreevarsAndCellvars(thread, callee_frame); 680 } 681 return Interpreter::execute(thread); 682} 683 684RawObject unimplementedTrampoline(Thread*, word) { 685 UNIMPLEMENTED("Trampoline"); 686} 687 688static inline RawObject builtinTrampolineImpl(Thread* thread, word arg, 689 word function_idx, 690 PrepareCallFunc prepare_call) { 691 // Warning: This code is using `RawXXX` variables for performance! This is 692 // despite the fact that we call functions that do potentially perform memory 693 // allocations. This is legal here because we always rely on the functions 694 // returning an up-to-date address and we make sure to never access any value 695 // produce before a call after that call. Be careful not to break this 696 // invariant if you change the code! 697 698 RawObject prepare_result = prepare_call( 699 thread, arg, Function::cast(thread->stackPeek(function_idx))); 700 if (prepare_result.isErrorException()) { 701 return prepare_result; 702 } 703 RawFunction function_obj = Function::cast(prepare_result); 704 705 RawObject result = NoneType::object(); 706 { 707 BuiltinFunction function = bit_cast<BuiltinFunction>( 708 SmallInt::cast(function_obj.stacksizeOrBuiltin()).asAlignedCPtr()); 709 710 word nargs = function_obj.totalArgs(); 711 Frame* callee_frame = thread->pushNativeFrame(nargs); 712 if (UNLIKELY(callee_frame == nullptr)) { 713 thread->stackDrop(nargs + 1); 714 return Error::exception(); 715 } 716 result = (*function)(thread, Arguments(callee_frame)); 717 // End scope so people do not accidentally use raw variables after the call 718 // which could have triggered a GC. 719 } 720 DCHECK(thread->isErrorValueOk(result), "error/exception mismatch"); 721 thread->popFrame(); 722 return result; 723} 724 725RawObject builtinTrampoline(Thread* thread, word nargs) { 726 return builtinTrampolineImpl(thread, nargs, /*function_idx=*/nargs, 727 preparePositionalCall); 728} 729 730RawObject builtinTrampolineKw(Thread* thread, word nargs) { 731 return builtinTrampolineImpl(thread, nargs, /*function_idx=*/nargs + 1, 732 prepareKeywordCall); 733} 734 735RawObject builtinTrampolineEx(Thread* thread, word flags) { 736 return builtinTrampolineImpl( 737 thread, flags, 738 /*function_idx=*/(flags & CallFunctionExFlag::VAR_KEYWORDS) ? 2 : 1, 739 prepareExplodeCall); 740} 741 742} // namespace py