[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/python/cpython/3.15/Include/internal/pycore_code.h [Back]  [Original]

#ifndef Py_INTERNAL_CODE_H
#define Py_INTERNAL_CODE_H
#ifdef __cplusplus
extern "C" {
#endif

#ifndef Py_BUILD_CORE
#  error "this header requires Py_BUILD_CORE define"
#endif

#include "pycore_backoff.h"     // _Py_BackoffCounter
#include "pycore_structs.h"     // _Py_CODEUNIT
#include "pycore_tstate.h"      // _PyThreadStateImpl


#define _PyCode_CODE(CO) _Py_RVALUE((_Py_CODEUNIT *)(CO)->co_code_adaptive)
#define _PyCode_NBYTES(CO) (Py_SIZE(CO) * (Py_ssize_t)sizeof(_Py_CODEUNIT))


/* These macros only remain defined for compatibility. */
#define _Py_OPCODE(word) ((word).op.code)
#define _Py_OPARG(word) ((word).op.arg)

static inline _Py_CODEUNIT
_py_make_codeunit(uint8_t opcode, uint8_t oparg)
{
    // No designated initialisers because of C++ compat
    _Py_CODEUNIT word;
    word.op.code = opcode;
    word.op.arg = oparg;
    return word;
}

static inline void
_py_set_opcode(_Py_CODEUNIT *word, uint8_t opcode)
{
    word->op.code = opcode;
}

#define _Py_MAKE_CODEUNIT(opcode, oparg) _py_make_codeunit((opcode), (oparg))
#define _Py_SET_OPCODE(word, opcode) _py_set_opcode(&(word), (opcode))


// We hide some of the newer PyCodeObject fields behind macros.
// This helps with backporting certain changes to 3.12.
#define _PyCode_HAS_EXECUTORS(CODE) \
    (CODE->co_executors != NULL)
#define _PyCode_HAS_INSTRUMENTATION(CODE) \
    (CODE->_co_instrumentation_version > 0)


extern PyStatus _PyCode_Init(PyInterpreterState *interp);
extern void _PyCode_Fini(PyInterpreterState *interp);


/* PEP 659
 * Specialization and quickening structs and helper functions
 */


// Inline caches. If you change the number of cache entries for an instruction,
// you must *also* update the number of cache entries in Lib/opcode.py and bump
// the magic number in Lib/importlib/_bootstrap_external.py!

#define CACHE_ENTRIES(cache) (sizeof(cache)/sizeof(_Py_CODEUNIT))

typedef struct {
    _Py_BackoffCounter counter;
    uint16_t module_keys_version;
    uint16_t builtin_keys_version;
    uint16_t index;
} _PyLoadGlobalCache;

#define INLINE_CACHE_ENTRIES_LOAD_GLOBAL CACHE_ENTRIES(_PyLoadGlobalCache)

typedef struct {
    _Py_BackoffCounter counter;
    uint16_t external_cache[4];
} _PyBinaryOpCache;

#define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyUnpackSequenceCache;

#define INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE \
    CACHE_ENTRIES(_PyUnpackSequenceCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyCompareOpCache;

#define INLINE_CACHE_ENTRIES_COMPARE_OP CACHE_ENTRIES(_PyCompareOpCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PySuperAttrCache;

#define INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR CACHE_ENTRIES(_PySuperAttrCache)

typedef struct {
    _Py_BackoffCounter counter;
    uint16_t version[2];
    uint16_t index;
} _PyAttrCache;

typedef struct {
    _Py_BackoffCounter counter;
    uint16_t type_version[2];
    union {
        uint16_t keys_version[2];
        uint16_t dict_offset;
    };
    uint16_t descr[4];
} _PyLoadMethodCache;


// MUST be the max(_PyAttrCache, _PyLoadMethodCache)
#define INLINE_CACHE_ENTRIES_LOAD_ATTR CACHE_ENTRIES(_PyLoadMethodCache)

#define INLINE_CACHE_ENTRIES_STORE_ATTR CACHE_ENTRIES(_PyAttrCache)

typedef struct {
    _Py_BackoffCounter counter;
    uint16_t func_version[2];
} _PyCallCache;

#define INLINE_CACHE_ENTRIES_CALL CACHE_ENTRIES(_PyCallCache)
#define INLINE_CACHE_ENTRIES_CALL_KW CACHE_ENTRIES(_PyCallCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyStoreSubscrCache;

#define INLINE_CACHE_ENTRIES_STORE_SUBSCR CACHE_ENTRIES(_PyStoreSubscrCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyForIterCache;

#define INLINE_CACHE_ENTRIES_FOR_ITER CACHE_ENTRIES(_PyForIterCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyGetIterCache;

#define INLINE_CACHE_ENTRIES_GET_ITER CACHE_ENTRIES(_PyGetIterCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PySendCache;

#define INLINE_CACHE_ENTRIES_SEND CACHE_ENTRIES(_PySendCache)

typedef struct {
    _Py_BackoffCounter counter;
    uint16_t version[2];
} _PyToBoolCache;

#define INLINE_CACHE_ENTRIES_TO_BOOL CACHE_ENTRIES(_PyToBoolCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyContainsOpCache;

#define INLINE_CACHE_ENTRIES_CONTAINS_OP CACHE_ENTRIES(_PyContainsOpCache)

typedef struct {
    _Py_BackoffCounter counter;
} _PyCallFunctionExCache;

#define INLINE_CACHE_ENTRIES_CALL_FUNCTION_EX CACHE_ENTRIES(_PyCallFunctionExCache)

/* "Locals plus" for a code object is the set of locals + cell vars +
 * free vars.  This relates to variable names as well as offsets into
 * the "fast locals" storage array of execution frames.  The compiler
 * builds the list of names, their offsets, and the corresponding
 * kind of local.
 *
 * Those kinds represent the source of the initial value and the
 * variable's scope (as related to closures).  A "local" is an
 * argument or other variable defined in the current scope.  A "free"
 * variable is one that is defined in an outer scope and comes from
 * the function's closure.  A "cell" variable is a local that escapes
 * into an inner function as part of a closure, and thus must be
 * wrapped in a cell.  Any "local" can also be a "cell", but the
 * "free" kind is mutually exclusive with both.
 */

// Note that these all fit within a byte, as do combinations.
#define CO_FAST_ARG_POS (0x02)  // pos-only, pos-or-kw, varargs
#define CO_FAST_ARG_KW  (0x04)  // kw-only, pos-or-kw, varkwargs
#define CO_FAST_ARG_VAR (0x08)  // varargs, varkwargs
#define CO_FAST_ARG     (CO_FAST_ARG_POS | CO_FAST_ARG_KW | CO_FAST_ARG_VAR)
#define CO_FAST_HIDDEN  (0x10)
#define CO_FAST_LOCAL   (0x20)
#define CO_FAST_CELL    (0x40)
#define CO_FAST_FREE    (0x80)

typedef unsigned char _PyLocals_Kind;

static inline _PyLocals_Kind
_PyLocals_GetKind(PyObject *kinds, int i)
{
    assert(PyBytes_Check(kinds));
    assert(0 tlbc_index;
    if (idx < code->size && code->entries[idx] != NULL) {
        return (_Py_CODEUNIT *) code->entries[idx];
    }
    return NULL;
}

// Return a pointer to the thread-local bytecode for the current thread,
// creating it if necessary.
PyAPI_FUNC(_Py_CODEUNIT *) _PyCode_GetTLBC(PyCodeObject *co);

// Reserve an index for the current thread into thread-local bytecode
// arrays
//
// Returns the reserved index or -1 on error.
extern int32_t _Py_ReserveTLBCIndex(PyInterpreterState *interp);

// Release an index returned by _Py_ReserveTLBCIndex() that was never stored
// in a PyThreadState.
extern void _Py_UnreserveTLBCIndex(PyInterpreterState *interp, int32_t index);

// Release the current thread's index into thread-local bytecode arrays
extern void _Py_ClearTLBCIndex(_PyThreadStateImpl *tstate);

// Free all TLBC copies not associated with live threads.
//
// Returns 0 on success or -1 on error.
extern int _Py_ClearUnusedTLBC(PyInterpreterState *interp);
#endif


typedef struct {
    int total;
    struct co_locals_counts {
        int total;
        struct {
            int total;
            int numposonly;
            int numposorkw;
            int numkwonly;
            int varargs;
            int varkwargs;
        } args;
        int numpure;
        struct {
            int total;
            // numargs does not contribute to locals.total.
            int numargs;
            int numothers;
        } cells;
        struct {
            int total;
            int numpure;
            int numcells;
        } hidden;
    } locals;
    int numfree;  // nonlocal
    struct co_unbound_counts {
        int total;
        struct {
            int total;
            int numglobal;
            int numbuiltin;
            int numunknown;
        } globals;
        int numattrs;
        int numunknown;
    } unbound;
} _PyCode_var_counts_t;

PyAPI_FUNC(void) _PyCode_GetVarCounts(
        PyCodeObject *,
        _PyCode_var_counts_t *);
PyAPI_FUNC(int) _PyCode_SetUnboundVarCounts(
        PyThreadState *,
        PyCodeObject *,
        _PyCode_var_counts_t *,
        PyObject *globalnames,
        PyObject *attrnames,
        PyObject *globalsns,
        PyObject *builtinsns);


/* "Stateless" code is a function or code object which does not rely on
 * external state or internal state.  It may rely on arguments and
 * builtins, but not globals or a closure.  Thus it does not rely
 * on __globals__ or __closure__, and a stateless function
 * is equivalent to its code object.
 *
 * Stateless code also does not keep any persistent state
 * of its own, so it can't have any executors, monitoring,
 * instrumentation, or "extras" (i.e. co_extra).
 *
 * Stateless code may create nested functions, including closures.
 * However, nested functions must themselves be stateless, except they
 * *can* close on the enclosing locals.
 *
 * Stateless code may return any value, including nested functions and closures.
 *
 * Stateless code that takes no arguments and doesn't return anything
 * may be treated like a script.
 *
 * We consider stateless code to be "portable" if it does not return
 * any object that holds a reference to any of the code's locals.  Thus
 * generators and coroutines are not portable.  Likewise a function
 * that returns a closure is not portable.  The concept of
 * portability is useful in cases where the code is run
 * in a different execution context than where
 * the return value will be used. */

PyAPI_FUNC(int) _PyCode_CheckNoInternalState(PyCodeObject *, const char **);
PyAPI_FUNC(int) _PyCode_CheckNoExternalState(
        PyCodeObject *,
        _PyCode_var_counts_t *,
        const char **);
PyAPI_FUNC(int) _PyCode_VerifyStateless(
        PyThreadState *,
        PyCodeObject *,
        PyObject *globalnames,
        PyObject *globalsns,
        PyObject *builtinsns);

PyAPI_FUNC(int) _PyCode_CheckPureFunction(PyCodeObject *, const char **);
PyAPI_FUNC(int) _PyCode_ReturnsOnlyNone(PyCodeObject *);

/* Create a comparable key used to compare constants taking in account the
 * object type. It is used to make sure types are not coerced (e.g., float and
 * complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms
 *
 * Return (type(obj), obj, ...): a tuple with variable size (at least 2 items)
 * depending on the type and the value. The type is the first item to not
 * compare bytes and str which can raise a BytesWarning exception. */
extern PyObject* _PyCode_ConstantKey(PyObject *obj);


#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_CODE_H */

Web Proxy Viewer  |  New URL  |  Original Page