runtime/interpreter.h (446 lines of code) (raw):

/* Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) */ #pragma once #include "bytecode.h" #include "frame.h" #include "globals.h" #include "handles.h" #include "symbols.h" #include "trampolines.h" namespace py { class RawObject; class Frame; class Thread; // Bitset indicating how a cached binary operation needs to be called. enum BinaryOpFlags : uint8_t { kBinaryOpNone = 0, // Swap arguments when calling the method. kBinaryOpReflected = 1 << 0, // Retry alternative method when method returns `NotImplemented`. Should try // the non-reflected op if the `kBinaryOpReflected` flag is set and vice // versa. kBinaryOpNotImplementedRetry = 1 << 1, // This flag is set when the cached method is an in-place operation (such as // __iadd__). kInplaceBinaryOpRetry = 1 << 2, }; // Different caching strategies for the resolved location of a LOAD_ATTR enum class LoadAttrKind { kInstanceOffset = 1, kInstanceFunction, kInstanceProperty, kInstanceSlotDescr, kInstanceType, kInstanceTypeDescr, kModule, kType, kUnknown, }; enum class ICState { kAnamorphic, kMonomorphic, kPolymorphic, }; class Interpreter { public: enum class BinaryOp { ADD, SUB, MUL, MATMUL, TRUEDIV, FLOORDIV, MOD, DIVMOD, POW, LSHIFT, RSHIFT, AND, XOR, OR }; enum class Continue { NEXT, UNWIND, RETURN, YIELD, DEOPT, }; static const word kNumContinues = 5; using OpcodeHandler = Continue (*)(Thread* thread, word arg); virtual ~Interpreter(); // Initialize per-thread interpreter state. Must be called on each thread // before the interpreter can execute code on it. virtual void setupThread(Thread* thread) = 0; virtual void* entryAsm(const Function& function) = 0; virtual void setOpcodeCounting(bool enabled) = 0; static RawObject execute(Thread* thread); static RawObject resumeGenerator(Thread* thread, const GeneratorBase& generator, const Object& send_value); static RawObject resumeGeneratorWithRaise(Thread* thread, const GeneratorBase& generator, const Object& type, const Object& value, const Object& traceback); static RawObject call(Thread* thread, word nargs); static RawObject callEx(Thread* thread, word flags); static RawObject callKw(Thread* thread, word nargs); // Perform positional call of function `function`. Does not work for arbitrary // callables objects; that case requires `call`. static RawObject callFunction(Thread* thread, word nargs, RawObject function); // Calls __hash__ on `value`, checks result and postprocesses. Returns a // SmallInt or Error::exception(). static RawObject hash(Thread* thread, const Object& value); // batch concat/join <num> string objects on the stack (no conversion) static RawObject stringJoin(Thread* thread, RawObject* sp, word num); static RawObject isTrue(Thread* thread, RawObject value_obj); static RawObject callDescriptorGet(Thread* thread, const Object& descriptor, const Object& receiver, const Object& receiver_type); static RawObject callDescriptorSet(Thread* thread, const Object& descriptor, const Object& receiver, const Object& value); static RawObject callDescriptorDelete(Thread* thread, const Object& descriptor, const Object& receiver); // Lookup method in type of `receiver`. Only performs a lookup in the type, // not in `receiver` itself. As a shortcut this function does not create // `BoundMethod` objects hence the result must only be used with `callMethodX` // or `tailcallMethodX`. static RawObject lookupMethod(Thread* thread, const Object& receiver, SymbolId selector); // Call callable object without parameters. static RawObject call0(Thread* thread, const Object& callable); // Call callable object with 1 parameter. static RawObject call1(Thread* thread, const Object& callable, const Object& arg1); // Call callable object with 2 parameters. static RawObject call2(Thread* thread, const Object& callable, const Object& arg1, const Object& arg2); // Call callable object with 3 parameters. static RawObject call3(Thread* thread, const Object& callable, const Object& arg1, const Object& arg2, const Object& arg3); // Call callable object with 4 parameters. static RawObject call4(Thread* thread, const Object& callable, const Object& arg1, const Object& arg2, const Object& arg3, const Object& arg4); // Call callable object with 5 parameters. static RawObject call5(Thread* thread, const Object& callable, const Object& arg1, const Object& arg2, const Object& arg3, const Object& arg4, const Object& arg5); // Call callable object with 6 parameters. static RawObject call6(Thread* thread, const Object& callable, const Object& arg1, const Object& arg2, const Object& arg3, const Object& arg4, const Object& arg5, const Object& arg6); // Call method with 1 argument; must only be used with objects looked up via // `lookupMethod`. static RawObject callMethod1(Thread* thread, const Object& method, const Object& self); // Call method with 2 arguments; must only be used with objects looked up via // `lookupMethod`. static RawObject callMethod2(Thread* thread, const Object& method, const Object& self, const Object& other); // Call method with 3 arguments; must only be used with objects looked up via // `lookupMethod`. static RawObject callMethod3(Thread* thread, const Object& method, const Object& self, const Object& arg1, const Object& arg2); // Call method with 4 arguments; must only be used with objects looked up via // `lookupMethod`. static RawObject callMethod4(Thread* thread, const Object& method, const Object& self, const Object& arg1, const Object& arg2, const Object& arg3); struct PrepareCallableResult { RawObject function; word nargs; }; // Prepare the stack to for a positional or keyword call by normalizing the // callable object using prepareCallableObject(). // // Returns the concrete Function that should be called. Updates nargs if a // self object was unpacked from the callable and inserted into the stack. // // Not intended for public use; only here for testing purposes. static PrepareCallableResult prepareCallableCall(Thread* thread, word nargs, word callable_idx); static RawObject unaryOperation(Thread* thread, const Object& self, SymbolId selector); static RawObject binaryOperation(Thread* thread, BinaryOp op, const Object& left, const Object& right); static Continue binaryOpUpdateCache(Thread* thread, word arg, word cache); // Lookup and invoke a binary operation (like `__add__`, `__sub__`, ...). // Sets `method_out` and `flags_out` to the lookup result if it is possible // to cache it. static RawObject binaryOperationSetMethod(Thread* thread, BinaryOp op, const Object& left, const Object& right, Object* method_out, BinaryOpFlags* flags_out); // Calls a previously cached binary operation. Note that the caller still // needs to check for a `NotImplemented` result and call // `binaryOperationRetry()` if necessary. static RawObject binaryOperationWithMethod(Thread* thread, RawObject method, BinaryOpFlags flags, RawObject left, RawObject right); // Calls the normal binary operation if `flags` has the `kBinaryOpReflected` // and the `kBinaryOpNotImplementedRetry` bits are set; calls the reflected // operation if just `kBinaryOpNotImplementedRetry` is set. Raises an error // if any of the two operations raised `NotImplemented` or none was called. // // This represents the second half of the binary operation calling mechanism // after we attempted a first lookup and call. It is a separate function so we // can use it independently of the first lookup using inline caching. static RawObject binaryOperationRetry(Thread* thread, BinaryOp op, BinaryOpFlags flags, const Object& left, const Object& right); // Slow path for the BINARY_SUBSCR opcode that updates the cache at the given // index when appropriate. May also be used as a non-caching slow path by // passing a negative index. static Continue binarySubscrUpdateCache(Thread* thread, word cache); // Slow path for the STORE_SUBSCR opcode that updates the cache at the given // index when appropriate. May also be used as a non-caching slow path by // passing a negative index. static Continue storeSubscrUpdateCache(Thread* thread, word cache); static Continue compareInUpdateCache(Thread* thread, word cache); static RawObject inplaceOperation(Thread* thread, BinaryOp op, const Object& left, const Object& right); static Continue inplaceOpUpdateCache(Thread* thread, word arg, word cache); static RawObject inplaceOperationSetMethod(Thread* thread, BinaryOp op, const Object& left, const Object& right, Object* method_out, BinaryOpFlags* flags_out); static RawObject compareOperationRetry(Thread* thread, CompareOp op, BinaryOpFlags flags, const Object& left, const Object& right); static RawObject compareOperationSetMethod(Thread* thread, CompareOp op, const Object& left, const Object& right, Object* method_out, BinaryOpFlags* flags_out); static RawObject compareOperation(Thread* thread, CompareOp op, const Object& left, const Object& right); static Continue compareOpUpdateCache(Thread* thread, word arg, word cache); static RawObject createIterator(Thread* thread, const Object& iterable); static RawObject sequenceIterSearch(Thread* thread, const Object& value, const Object& container); static RawObject sequenceContains(Thread* thread, const Object& value, const Object& container); static RawObject sequenceContainsSetMethod(Thread* thread, const Object& value, const Object& container, Object* method_out); static RawObject unpackSequence(Thread* thread, word length, RawObject iterable); static RawObject loadAttrWithLocation(Thread* thread, RawObject receiver, RawObject location); static RawObject importAllFrom(Thread* thread, Frame* frame, const Object& object); // Process the operands to the RAISE_VARARGS bytecode into a pending exception // on ctx->thread. static void raise(Thread* thread, RawObject exc_obj, RawObject cause_obj); static RawObject storeAttrSetLocation(Thread* thread, const Object& object, const Object& name, const Object& value, Object* location_out); static void storeAttrWithLocation(Thread* thread, RawObject receiver, RawObject location, RawObject value); static SymbolId binaryOperationSelector(BinaryOp op); static SymbolId swappedBinaryOperationSelector(BinaryOp op); static SymbolId inplaceOperationSelector(BinaryOp op); static SymbolId comparisonSelector(CompareOp op); static SymbolId swappedComparisonSelector(CompareOp op); // Unwind the stack for a pending exception. A return value that is not // `Error::error()` indicates that we should exit the interpreter loop and // return that value. static RawObject unwind(Thread* thread); // Unwind an ExceptHandler from the stack, restoring the previous handler // state. static void unwindExceptHandler(Thread* thread, TryBlock block); // Pop from the block stack until a handler that cares about 'return' is // found, or the stack is emptied. A return value that is not `Error::error()` // indicates that we should exit the interpreter loop and return that value. static RawObject handleReturn(Thread* thread); // Opcode handlers // // Handlers that never exit the Frame return void, while those that could // return bool. // // A return value of true means the top Frame owned by this Interpreter is // finished. The dispatch loop will pop TOS, pop the Frame, and return the // popped value. For raised exceptions, this value will always be Error, and // for opcodes like RETURN_VALUE it will be the returned value. // // A return value of false means execution should continue as normal in the // current Frame. static Continue doBeforeAsyncWith(Thread* thread, word arg); static Continue doBeginFinally(Thread* thread, word arg); static Continue doBinaryAdd(Thread* thread, word arg); static Continue doBinaryAnd(Thread* thread, word arg); static Continue doBinaryFloorDivide(Thread* thread, word arg); static Continue doBinaryLshift(Thread* thread, word arg); static Continue doBinaryMatrixMultiply(Thread* thread, word arg); static Continue doBinaryModulo(Thread* thread, word arg); static Continue doBinaryMultiply(Thread* thread, word arg); static Continue doBinaryOpMonomorphic(Thread* thread, word arg); static Continue doBinaryOpPolymorphic(Thread* thread, word arg); static Continue doBinaryAddSmallInt(Thread* thread, word arg); static Continue doBinaryAndSmallInt(Thread* thread, word arg); static Continue doBinaryMulSmallInt(Thread* thread, word arg); static Continue doBinaryFloordivSmallInt(Thread* thread, word arg); static Continue doBinarySubSmallInt(Thread* thread, word arg); static Continue doBinaryOrSmallInt(Thread* thread, word arg); static Continue doBinaryOpAnamorphic(Thread* thread, word arg); static Continue doBinaryOr(Thread* thread, word arg); static Continue doBinaryPower(Thread* thread, word arg); static Continue doBinaryRshift(Thread* thread, word arg); static Continue doBinarySubscr(Thread* thread, word arg); static Continue doBinarySubscrDict(Thread* thread, word arg); static Continue doBinarySubscrList(Thread* thread, word arg); static Continue doBinarySubscrTuple(Thread* thread, word arg); static Continue doBinarySubscrMonomorphic(Thread* thread, word arg); static Continue doBinarySubscrPolymorphic(Thread* thread, word arg); static Continue doBinarySubscrAnamorphic(Thread* thread, word arg); static Continue doBinarySubtract(Thread* thread, word arg); static Continue doBinaryTrueDivide(Thread* thread, word arg); static Continue doBinaryXor(Thread* thread, word arg); static Continue doBuildListUnpack(Thread* thread, word arg); static Continue doBuildMap(Thread* thread, word arg); static Continue doBuildMapUnpack(Thread* thread, word arg); static Continue doBuildMapUnpackWithCall(Thread* thread, word arg); static Continue doBuildSet(Thread* thread, word arg); static Continue doBuildSetUnpack(Thread* thread, word arg); static Continue doBuildTupleUnpack(Thread* thread, word arg); static Continue doCallFinally(Thread* thread, word arg); static Continue doCallFunction(Thread* thread, word arg); static Continue doCallFunctionEx(Thread* thread, word arg); static Continue doCallFunctionKw(Thread* thread, word arg); static Continue doCallMethod(Thread* thread, word arg); static Continue doCallFunctionAnamorphic(Thread* thread, word arg); static Continue doCallFunctionTypeNew(Thread* thread, word arg); static Continue doCompareInAnamorphic(Thread* thread, word arg); static Continue doCompareInStr(Thread* thread, word arg); static Continue doCompareInTuple(Thread* thread, word arg); static Continue doCompareInDict(Thread* thread, word arg); static Continue doCompareInList(Thread* thread, word arg); static Continue doCompareInMonomorphic(Thread* thread, word arg); static Continue doCompareInPolymorphic(Thread* thread, word arg); static Continue doCompareIs(Thread* thread, word arg); static Continue doCompareIsNot(Thread* thread, word arg); static Continue doCompareOp(Thread* thread, word arg); static Continue doCompareOpMonomorphic(Thread* thread, word arg); static Continue doCompareOpPolymorphic(Thread* thread, word arg); static Continue doCompareEqSmallInt(Thread* thread, word arg); static Continue doCompareGtSmallInt(Thread* thread, word arg); static Continue doCompareLtSmallInt(Thread* thread, word arg); static Continue doCompareGeSmallInt(Thread* thread, word arg); static Continue doCompareNeSmallInt(Thread* thread, word arg); static Continue doCompareLeSmallInt(Thread* thread, word arg); static Continue doCompareEqStr(Thread* thread, word arg); static Continue doCompareNeStr(Thread* thread, word arg); static Continue doCompareOpAnamorphic(Thread* thread, word arg); static Continue doDeleteAttr(Thread* thread, word arg); static Continue doDeleteSubscr(Thread* thread, word arg); static Continue doEndAsyncFor(Thread* thread, word arg); static Continue doEndFinally(Thread* thread, word arg); static Continue doForIter(Thread* thread, word arg); static Continue doForIterAnamorphic(Thread* thread, word arg); static Continue doForIterDict(Thread* thread, word arg); static Continue doForIterGenerator(Thread* thread, word arg); static Continue doForIterList(Thread* thread, word arg); static Continue doForIterMonomorphic(Thread* thread, word arg); static Continue doForIterPolymorphic(Thread* thread, word arg); static Continue doForIterRange(Thread* thread, word arg); static Continue doForIterStr(Thread* thread, word arg); static Continue doForIterTuple(Thread* thread, word arg); static Continue doForIterUncached(Thread* thread, word arg); static Continue doFormatValue(Thread* thread, word arg); static Continue doGetAiter(Thread* thread, word arg); static Continue doGetAnext(Thread* thread, word arg); static Continue doGetAwaitable(Thread* thread, word arg); static Continue doGetIter(Thread* thread, word arg); static Continue doGetYieldFromIter(Thread* thread, word arg); static Continue doImportFrom(Thread* thread, word arg); static Continue doImportName(Thread* thread, word arg); static Continue doInplaceAdd(Thread* thread, word arg); static Continue doInplaceAddSmallInt(Thread* thread, word arg); static Continue doInplaceAnd(Thread* thread, word arg); static Continue doInplaceFloorDivide(Thread* thread, word arg); static Continue doInplaceLshift(Thread* thread, word arg); static Continue doInplaceMatrixMultiply(Thread* thread, word arg); static Continue doInplaceModulo(Thread* thread, word arg); static Continue doInplaceMultiply(Thread* thread, word arg); static Continue doInplaceOpMonomorphic(Thread* thread, word arg); static Continue doInplaceOpPolymorphic(Thread* thread, word arg); static Continue doInplaceOpAnamorphic(Thread* thread, word arg); static Continue doInplaceOr(Thread* thread, word arg); static Continue doInplacePower(Thread* thread, word arg); static Continue doInplaceRshift(Thread* thread, word arg); static Continue doInplaceSubtract(Thread* thread, word arg); static Continue doInplaceSubSmallInt(Thread* thread, word arg); static Continue doInplaceTrueDivide(Thread* thread, word arg); static Continue doInplaceXor(Thread* thread, word arg); static Continue doInvalidBytecode(Thread* thread, word arg); static Continue doLoadAttr(Thread* thread, word arg); static Continue doLoadAttrAnamorphic(Thread* thread, word arg); static Continue doLoadAttrInstance(Thread* thread, word arg); static Continue doLoadAttrInstanceTypeBoundMethod(Thread* thread, word arg); static Continue doLoadAttrInstanceProperty(Thread* thread, word arg); static Continue doLoadAttrInstanceSlotDescr(Thread* thread, word arg); static Continue doLoadAttrInstanceType(Thread* thread, word arg); static Continue doLoadAttrInstanceTypeDescr(Thread* thread, word arg); static Continue doLoadAttrModule(Thread* thread, word arg); static Continue doLoadAttrPolymorphic(Thread* thread, word arg); static Continue doLoadAttrType(Thread* thread, word arg); static Continue doLoadBool(Thread* thread, word arg); static Continue doLoadDeref(Thread* thread, word arg); static Continue doLoadFast(Thread* thread, word arg); static Continue doLoadFastReverse(Thread* thread, word arg); static Continue doLoadFastReverseUnchecked(Thread* thread, word arg); static Continue doLoadMethod(Thread* thread, word arg); static Continue doLoadMethodAnamorphic(Thread* thread, word arg); static Continue doLoadMethodInstanceFunction(Thread* thread, word arg); static Continue doLoadMethodPolymorphic(Thread* thread, word arg); static Continue doLoadName(Thread* thread, word arg); static Continue doPopExcept(Thread* thread, word arg); static Continue doPopFinally(Thread* thread, word arg); static Continue doRaiseVarargs(Thread* thread, word arg); static Continue doReturnValue(Thread* thread, word arg); static Continue doSetupWith(Thread* thread, word arg); static Continue doStoreAttr(Thread* thread, word arg); static Continue doStoreAttrInstance(Thread* thread, word arg); static Continue doStoreAttrInstanceOverflow(Thread* thread, word arg); static Continue doStoreAttrInstanceOverflowUpdate(Thread* thread, word arg); static Continue doStoreAttrInstanceUpdate(Thread* thread, word arg); static Continue doStoreAttrPolymorphic(Thread* thread, word arg); static Continue doStoreAttrAnamorphic(Thread* thread, word arg); static Continue doStoreSubscr(Thread* thread, word arg); static Continue doStoreSubscrDict(Thread* thread, word arg); static Continue doStoreSubscrList(Thread* thread, word arg); static Continue doStoreSubscrMonomorphic(Thread* thread, word arg); static Continue doStoreSubscrPolymorphic(Thread* thread, word arg); static Continue doStoreSubscrAnamorphic(Thread* thread, word arg); static Continue doUnaryInvert(Thread* thread, word arg); static Continue doUnaryNegative(Thread* thread, word arg); static Continue doUnaryNot(Thread* thread, word arg); static Continue doUnaryPositive(Thread* thread, word arg); static Continue doUnpackEx(Thread* thread, word arg); static Continue doUnpackSequence(Thread* thread, word arg); static Continue doWithCleanupFinish(Thread* thread, word arg); static Continue doWithCleanupStart(Thread* thread, word arg); static Continue doYieldFrom(Thread* thread, word arg); static Continue doYieldValue(Thread* thread, word arg); static Continue doBuildConstKeyMap(Thread* thread, word arg); static Continue doBuildList(Thread* thread, word arg); static Continue doBuildSlice(Thread* thread, word arg); static Continue doBuildString(Thread* thread, word arg); static Continue doBuildTuple(Thread* thread, word arg); static Continue doDeleteDeref(Thread* thread, word arg); static Continue doDeleteFast(Thread* thread, word arg); static Continue doDeleteGlobal(Thread* thread, word arg); static Continue doDeleteName(Thread* thread, word arg); static Continue doDupTop(Thread* thread, word arg); static Continue doDupTopTwo(Thread* thread, word arg); static Continue doImportStar(Thread* thread, word arg); static Continue doJumpAbsolute(Thread* thread, word arg); static Continue doJumpForward(Thread* thread, word arg); static Continue doJumpIfFalseOrPop(Thread* thread, word arg); static Continue doJumpIfTrueOrPop(Thread* thread, word arg); static Continue doListAppend(Thread* thread, word arg); static Continue doLoadBuildClass(Thread* thread, word arg); static Continue doLoadClassDeref(Thread* thread, word arg); static Continue doLoadClosure(Thread* thread, word arg); static Continue doLoadConst(Thread* thread, word arg); static Continue doLoadGlobal(Thread* thread, word arg); static Continue doLoadGlobalCached(Thread* thread, word arg); static Continue doLoadImmediate(Thread* thread, word arg); static Continue doMakeFunction(Thread* thread, word arg); static Continue doMapAdd(Thread* thread, word arg); static Continue doNop(Thread* thread, word arg); static Continue doPopBlock(Thread* thread, word arg); static Continue doPopJumpIfFalse(Thread* thread, word arg); static Continue doPopJumpIfTrue(Thread* thread, word arg); static Continue doPopTop(Thread* thread, word arg); static Continue doPrintExpr(Thread* thread, word arg); static Continue doRotThree(Thread* thread, word arg); static Continue doRotTwo(Thread* thread, word arg); static Continue doRotFour(Thread* thread, word arg); static Continue doSetAdd(Thread* thread, word arg); static Continue doSetupAnnotations(Thread* thread, word arg); static Continue doSetupAsyncWith(Thread* thread, word arg); static Continue doSetupFinally(Thread* thread, word arg); static Continue doStoreAnnotation(Thread* thread, word arg); static Continue doStoreDeref(Thread* thread, word arg); static Continue doStoreFast(Thread* thread, word arg); static Continue doStoreFastReverse(Thread* thread, word arg); static Continue doStoreGlobal(Thread* thread, word arg); static Continue doStoreGlobalCached(Thread* thread, word arg); static Continue doStoreName(Thread* thread, word arg); // Call an interpreted function (this captures the part of the CALL_FUNCTION // process after intrinsics are processed and it has been determined that the // callable is an interpreted function). static Continue callInterpreted(Thread* thread, word nargs, RawFunction function); // Resolve a callable object to a function (resolving `__call__` descriptors // as necessary). // This is a helper for `prepareCallableCall`: `prepareCallableCall` starts // out with shortcuts with the common cases and only calls this function for // the remaining rare cases with the expectation that this function is not // inlined. static PrepareCallableResult prepareCallableCallDunderCall(Thread* thread, word nargs, word callable_idx); // If the given GeneratorBase is suspended at a YIELD_FROM instruction, return // its subiterator. Otherwise, return None. static RawObject findYieldFrom(RawGeneratorBase gen); private: // Common functionality for opcode handlers that dispatch to binary and // inplace operations static Continue doBinaryOperation(BinaryOp op, Thread* thread); static Continue doInplaceOperation(BinaryOp op, Thread* thread); static Continue doUnaryOperation(SymbolId selector, Thread* thread); // Slow path for the FOR_ITER opcode that updates the cache at the given index // when appropriate. May also be used as a non-caching slow path by passing a // negative index. static Continue forIterUpdateCache(Thread* thread, word arg, word cache); static Continue forIter(Thread* thread, RawObject next_method, word arg); // Slow path for isTrue check. Does a __bool__ method call, etc. static RawObject isTrueSlowPath(Thread* thread, RawObject value_obj); // Perform a method call at the end of an opcode handler. The benefit over // using `callMethod1()` is that we avoid recursively starting a new // interpreter loop when the target is a python function. Must only be used // on objects looked up via `lookupMethod`. static Continue tailcallMethod1(Thread* thread, RawObject method, RawObject self); // Call callable with `arg` parameters at the end of an opcode handler. Use // this when the number of parameters is more than 2. static Continue tailcall(Thread* thread, word arg); // Call function object at frame[nargs]. The result functionc all result // is pushed onto the stack. static Continue tailcallFunction(Thread* thread, word nargs, RawObject function_obj); // Given a non-Function object in `callable`, attempt to normalize it to a // Function by either unpacking a BoundMethod or looking up the object's // __call__ method, iterating multiple times if necessary. // // On success, `callable` will contain the Function to call, and the return // value will be a bool indicating whether or not `self` was populated with an // object unpacked from a BoundMethod. // // On failure, Error is returned and `callable` may have been modified. static RawObject prepareCallable(Thread* thread, Object* callable, Object* self); // Prepare the stack for an explode call by normalizing the callable object // using prepareCallableObject(). // // Returns the concrete Function that should be called. static RawObject prepareCallableEx(Thread* thread, word callable_idx); // Perform a positional or keyword call. Used by doCallFunction() and // doCallFunctionKw(). static Continue handleCall(Thread* thread, word nargs, word callable_idx, PrepareCallFunc prepare_args, Function::Entry (RawFunction::*get_entry)() const); // Call a function through its trampoline, pushing the result on the stack. static Continue callTrampoline(Thread* thread, Function::Entry entry, word nargs, RawObject* post_call_sp); static Continue retryLoadAttrCached(Thread* thread, word arg, word cache); static Continue loadAttrUpdateCache(Thread* thread, word arg, word cache); static Continue storeAttrUpdateCache(Thread* thread, word arg, word cache); static Continue storeSubscr(Thread* thread, RawObject set_item_method); static Continue callFunctionTypeNewUpdateCache(Thread* thread, word arg, word cache); static Continue loadMethodUpdateCache(Thread* thread, word arg, word cache); using BinaryOpFallbackHandler = Continue (*)(Thread* thread, word arg, BinaryOpFlags flags); static Continue binaryOp(Thread* thread, word arg, RawObject method, BinaryOpFlags flags, RawObject left, RawObject right, BinaryOpFallbackHandler fallback); static Continue binaryOpFallback(Thread* thread, word arg, BinaryOpFlags flags); static Continue compareOpFallback(Thread* thread, word arg, BinaryOpFlags flags); static Continue inplaceOpFallback(Thread* thread, word arg, BinaryOpFlags flags); static RawObject awaitableIter(Thread* thread, const char* invalid_type_message); }; Interpreter* createCppInterpreter(); } // namespace py